mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
coretext shaper owns CFReleaseThread, works on both Metal and OpenGL now
This commit is contained in:
@ -5,6 +5,8 @@ const Allocator = std.mem.Allocator;
|
|||||||
const macos = @import("macos");
|
const macos = @import("macos");
|
||||||
const trace = @import("tracy").trace;
|
const trace = @import("tracy").trace;
|
||||||
const font = @import("../main.zig");
|
const font = @import("../main.zig");
|
||||||
|
const os = @import("../../os/main.zig");
|
||||||
|
const terminal = @import("../../terminal/main.zig");
|
||||||
const Face = font.Face;
|
const Face = font.Face;
|
||||||
const Collection = font.Collection;
|
const Collection = font.Collection;
|
||||||
const DeferredFace = font.DeferredFace;
|
const DeferredFace = font.DeferredFace;
|
||||||
@ -14,7 +16,7 @@ const Library = font.Library;
|
|||||||
const SharedGrid = font.SharedGrid;
|
const SharedGrid = font.SharedGrid;
|
||||||
const Style = font.Style;
|
const Style = font.Style;
|
||||||
const Presentation = font.Presentation;
|
const Presentation = font.Presentation;
|
||||||
const terminal = @import("../../terminal/main.zig");
|
const CFReleaseThread = os.CFReleaseThread;
|
||||||
|
|
||||||
const log = std.log.scoped(.font_shaper);
|
const log = std.log.scoped(.font_shaper);
|
||||||
|
|
||||||
@ -62,6 +64,12 @@ pub const Shaper = struct {
|
|||||||
/// sent to the release thread when endFrame is called.
|
/// sent to the release thread when endFrame is called.
|
||||||
cf_release_pool: std.ArrayListUnmanaged(*anyopaque),
|
cf_release_pool: std.ArrayListUnmanaged(*anyopaque),
|
||||||
|
|
||||||
|
/// Dedicated thread for releasing CoreFoundation objects. Some objects,
|
||||||
|
/// such as those produced by CoreText, have excessively slow release
|
||||||
|
/// callback logic.
|
||||||
|
cf_release_thread: *CFReleaseThread,
|
||||||
|
cf_release_thr: std.Thread,
|
||||||
|
|
||||||
const CellBuf = std.ArrayListUnmanaged(font.shape.Cell);
|
const CellBuf = std.ArrayListUnmanaged(font.shape.Cell);
|
||||||
const CodepointList = std.ArrayListUnmanaged(Codepoint);
|
const CodepointList = std.ArrayListUnmanaged(Codepoint);
|
||||||
const Codepoint = struct {
|
const Codepoint = struct {
|
||||||
@ -215,6 +223,20 @@ pub const Shaper = struct {
|
|||||||
const cached_fonts = std.ArrayList(?*macos.foundation.Dictionary).init(alloc);
|
const cached_fonts = std.ArrayList(?*macos.foundation.Dictionary).init(alloc);
|
||||||
errdefer cached_fonts.deinit();
|
errdefer cached_fonts.deinit();
|
||||||
|
|
||||||
|
// Create the CF release thread.
|
||||||
|
var cf_release_thread = try alloc.create(CFReleaseThread);
|
||||||
|
errdefer alloc.destroy(cf_release_thread);
|
||||||
|
cf_release_thread.* = try CFReleaseThread.init(alloc);
|
||||||
|
errdefer cf_release_thread.deinit();
|
||||||
|
|
||||||
|
// Start the CF release thread.
|
||||||
|
var cf_release_thr = try std.Thread.spawn(
|
||||||
|
.{},
|
||||||
|
CFReleaseThread.threadMain,
|
||||||
|
.{cf_release_thread},
|
||||||
|
);
|
||||||
|
cf_release_thr.setName("cf_release") catch {};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.cell_buf = .{},
|
.cell_buf = .{},
|
||||||
@ -223,6 +245,8 @@ pub const Shaper = struct {
|
|||||||
.writing_direction = writing_direction,
|
.writing_direction = writing_direction,
|
||||||
.cached_fonts = cached_fonts,
|
.cached_fonts = cached_fonts,
|
||||||
.cf_release_pool = .{},
|
.cf_release_pool = .{},
|
||||||
|
.cf_release_thread = cf_release_thread,
|
||||||
|
.cf_release_thr = cf_release_thr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +271,15 @@ pub const Shaper = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.cf_release_pool.deinit(self.alloc);
|
self.cf_release_pool.deinit(self.alloc);
|
||||||
|
|
||||||
|
// Stop the CF release thread
|
||||||
|
{
|
||||||
|
self.cf_release_thread.stop.notify() catch |err|
|
||||||
|
log.err("error notifying cf release thread to stop, may stall err={}", .{err});
|
||||||
|
self.cf_release_thr.join();
|
||||||
|
}
|
||||||
|
self.cf_release_thread.deinit();
|
||||||
|
self.alloc.destroy(self.cf_release_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release all cached fonts.
|
/// Release all cached fonts.
|
||||||
@ -258,6 +291,38 @@ pub const Shaper = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn endFrame(self: *Shaper) void {
|
||||||
|
if (self.cf_release_pool.items.len == 0) return;
|
||||||
|
|
||||||
|
// Get all the items in the pool as an owned slice so we can
|
||||||
|
// send it to the dedicated release thread.
|
||||||
|
const items = self.cf_release_pool.toOwnedSlice(self.alloc) catch |err| {
|
||||||
|
log.warn("error converting release pool to owned slice, slow release err={}", .{err});
|
||||||
|
for (self.cf_release_pool.items) |ref| macos.foundation.CFRelease(ref);
|
||||||
|
self.cf_release_pool.clearRetainingCapacity();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the items. If the send succeeds then we wake up the
|
||||||
|
// thread to process the items. If the send fails then do a manual
|
||||||
|
// cleanup.
|
||||||
|
if (self.cf_release_thread.mailbox.push(.{ .release = .{
|
||||||
|
.refs = items,
|
||||||
|
.alloc = self.alloc,
|
||||||
|
} }, .{ .forever = {} }) != 0) {
|
||||||
|
self.cf_release_thread.wakeup.notify() catch |err| {
|
||||||
|
log.warn(
|
||||||
|
"error notifying cf release thread to wake up, may stall err={}",
|
||||||
|
.{err},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (items) |ref| macos.foundation.CFRelease(ref);
|
||||||
|
self.alloc.free(items);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn runIterator(
|
pub fn runIterator(
|
||||||
self: *Shaper,
|
self: *Shaper,
|
||||||
grid: *SharedGrid,
|
grid: *SharedGrid,
|
||||||
|
@ -136,12 +136,6 @@ layer: objc.Object, // CAMetalLayer
|
|||||||
/// a display link.
|
/// a display link.
|
||||||
display_link: ?DisplayLink = null,
|
display_link: ?DisplayLink = null,
|
||||||
|
|
||||||
/// Dedicated thread for releasing CoreFoundation objects some objects,
|
|
||||||
/// such as those produced by CoreText, have excessively slow release
|
|
||||||
/// callback logic.
|
|
||||||
cf_release_thread: CFReleaseThread,
|
|
||||||
cf_release_thr: std.Thread,
|
|
||||||
|
|
||||||
/// Custom shader state. This is only set if we have custom shaders.
|
/// Custom shader state. This is only set if we have custom shaders.
|
||||||
custom_shader_state: ?CustomShaderState = null,
|
custom_shader_state: ?CustomShaderState = null,
|
||||||
|
|
||||||
@ -598,9 +592,6 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
|||||||
.cursor_color = options.config.cursor_color,
|
.cursor_color = options.config.cursor_color,
|
||||||
.current_background_color = options.config.background,
|
.current_background_color = options.config.background,
|
||||||
|
|
||||||
.cf_release_thread = undefined,
|
|
||||||
.cf_release_thr = undefined,
|
|
||||||
|
|
||||||
// Render state
|
// Render state
|
||||||
.cells = .{},
|
.cells = .{},
|
||||||
.uniforms = .{
|
.uniforms = .{
|
||||||
@ -698,18 +689,6 @@ pub fn loopEnter(self: *Metal, thr: *renderer.Thread) !void {
|
|||||||
&thr.draw_now,
|
&thr.draw_now,
|
||||||
);
|
);
|
||||||
display_link.start() catch {};
|
display_link.start() catch {};
|
||||||
|
|
||||||
// Create the CF release thread.
|
|
||||||
self.cf_release_thread = try CFReleaseThread.init(self.alloc);
|
|
||||||
errdefer self.cf_release_thread.deinit();
|
|
||||||
|
|
||||||
// Start the CF release thread.
|
|
||||||
self.cf_release_thr = try std.Thread.spawn(
|
|
||||||
.{},
|
|
||||||
CFReleaseThread.threadMain,
|
|
||||||
.{&self.cf_release_thread},
|
|
||||||
);
|
|
||||||
self.cf_release_thr.setName("cf_release") catch {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called by renderer.Thread when it exits the main loop.
|
/// Called by renderer.Thread when it exits the main loop.
|
||||||
@ -722,15 +701,6 @@ pub fn loopExit(self: *Metal) void {
|
|||||||
// is gone which is fine.
|
// is gone which is fine.
|
||||||
const display_link = self.display_link orelse return;
|
const display_link = self.display_link orelse return;
|
||||||
display_link.stop() catch {};
|
display_link.stop() catch {};
|
||||||
|
|
||||||
// Stop the CF release thread
|
|
||||||
{
|
|
||||||
self.cf_release_thread.stop.notify() catch |err|
|
|
||||||
log.err("error notifying cf release thread to stop, may stall err={}", .{err});
|
|
||||||
self.cf_release_thr.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cf_release_thread.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn displayLinkCallback(
|
fn displayLinkCallback(
|
||||||
@ -1028,22 +998,9 @@ pub fn updateFrame(
|
|||||||
&critical.color_palette,
|
&critical.color_palette,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (self.font_shaper.cf_release_pool.items.len > 0) {
|
// Notify our shaper we're done for the frame. For some shapers like
|
||||||
const alloc = self.font_shaper.alloc;
|
// CoreText this triggers off-thread cleanup logic.
|
||||||
const items = try self.font_shaper.cf_release_pool.toOwnedSlice(alloc);
|
self.font_shaper.endFrame();
|
||||||
if (self.cf_release_thread.mailbox.push(
|
|
||||||
.{ .release = .{
|
|
||||||
.refs = items,
|
|
||||||
.alloc = alloc,
|
|
||||||
} },
|
|
||||||
.{ .forever = {} },
|
|
||||||
) != 0) {
|
|
||||||
try self.cf_release_thread.wakeup.notify();
|
|
||||||
} else {
|
|
||||||
for (items) |ref| macos.foundation.CFRelease(ref);
|
|
||||||
alloc.free(items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update our viewport pin
|
// Update our viewport pin
|
||||||
self.cells_viewport = critical.viewport_pin;
|
self.cells_viewport = critical.viewport_pin;
|
||||||
|
@ -732,6 +732,10 @@ pub fn updateFrame(
|
|||||||
critical.cursor_style,
|
critical.cursor_style,
|
||||||
&critical.color_palette,
|
&critical.color_palette,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Notify our shaper we're done for the frame. For some shapers like
|
||||||
|
// CoreText this triggers off-thread cleanup logic.
|
||||||
|
self.font_shaper.endFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user