From 4325dc51bc47eea67238bcbcd8f556dab9562342 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 22 Jun 2024 20:32:24 -0700 Subject: [PATCH] font: coretext shaper owns the cf release pool --- src/font/shaper/coretext.zig | 276 +++++++++-------------------------- src/renderer/Metal.zig | 25 +--- src/renderer/OpenGL.zig | 11 +- 3 files changed, 79 insertions(+), 233 deletions(-) diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index cbac71ec3..5da08b214 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const macos = @import("macos"); @@ -49,13 +50,18 @@ pub const Shaper = struct { /// and releasing many objects when shaping. writing_direction: *macos.foundation.Array, - /// List where we cache fonts, so we don't have to - /// remake them for every single shaping operation. + /// List where we cache fonts, so we don't have to remake them for + /// every single shaping operation. /// - /// Fonts are cached as attribute dictionaries to - /// be applied directly to attributed strings. + /// Fonts are cached as attribute dictionaries to be applied directly to + /// attributed strings. cached_fonts: std.ArrayList(?*macos.foundation.Dictionary), + /// The list of CoreFoundation objects to release on the dedicated + /// release thread. This is built up over the course of shaping and + /// sent to the release thread when endFrame is called. + cf_release_pool: std.ArrayListUnmanaged(*anyopaque), + const CellBuf = std.ArrayListUnmanaged(font.shape.Cell); const CodepointList = std.ArrayListUnmanaged(Codepoint); const Codepoint = struct { @@ -209,13 +215,14 @@ pub const Shaper = struct { const cached_fonts = std.ArrayList(?*macos.foundation.Dictionary).init(alloc); errdefer cached_fonts.deinit(); - return Shaper{ + return .{ .alloc = alloc, .cell_buf = .{}, .run_state = run_state, .features = feats, .writing_direction = writing_direction, .cached_fonts = cached_fonts, + .cf_release_pool = .{}, }; } @@ -227,6 +234,19 @@ pub const Shaper = struct { self.releaseCachedFonts(); self.cached_fonts.deinit(); + + if (self.cf_release_pool.items.len > 0) { + for (self.cf_release_pool.items) |ref| macos.foundation.CFRelease(ref); + + // For tests this logic is normal because we don't want to + // wait for a release thread. But in production this is a bug + // and we should warn. + if (comptime !builtin.is_test) log.warn( + "BUG: CFRelease pool was not empty, releasing remaining objects", + .{}, + ); + } + self.cf_release_pool.deinit(self.alloc); } /// Release all cached fonts. @@ -256,13 +276,12 @@ pub const Shaper = struct { }; } - /// Expects an ArrayList `cf_release_pool` in which `CFTypeRef`s - /// can be placed, which guarantees that they will be `CFRelease`d - /// eventually. + /// Note that this will accumulate garbage in the release pool. The + /// caller must ensure you're properly calling endFrame to release + /// all the objects. pub fn shape( self: *Shaper, run: font.shape.TextRun, - cf_release_pool: *std.ArrayList(*anyopaque), ) ![]const font.shape.Cell { const state = &self.run_state; @@ -297,25 +316,24 @@ pub const Shaper = struct { const attr_dict: *macos.foundation.Dictionary = try self.getFont( run.grid, run.font_index, - cf_release_pool, ); // Make room for the attributed string and the CTLine. - try cf_release_pool.ensureUnusedCapacity(3); + try self.cf_release_pool.ensureUnusedCapacity(self.alloc, 3); const str = macos.foundation.String.createWithCharactersNoCopy(state.unichars.items); - cf_release_pool.appendAssumeCapacity(str); + self.cf_release_pool.appendAssumeCapacity(str); // Create an attributed string from our string const attr_str = try macos.foundation.AttributedString.create( str, attr_dict, ); - cf_release_pool.appendAssumeCapacity(attr_str); + self.cf_release_pool.appendAssumeCapacity(attr_str); // We should always have one run because we do our own run splitting. const line = try macos.text.Line.createWithAttributedString(attr_str); - cf_release_pool.appendAssumeCapacity(line); + self.cf_release_pool.appendAssumeCapacity(line); // This keeps track of the current offsets within a single cell. var cell_offset: struct { @@ -411,7 +429,6 @@ pub const Shaper = struct { self: *Shaper, grid: *font.SharedGrid, index: font.Collection.Index, - cf_release_pool: *std.ArrayList(*anyopaque), ) !*macos.foundation.Dictionary { const index_int = index.int(); @@ -426,7 +443,8 @@ pub const Shaper = struct { return cached; } - try cf_release_pool.ensureUnusedCapacity(3); + // Features dictionary, font descriptor, font + try self.cf_release_pool.ensureUnusedCapacity(self.alloc, 3); const run_font = font: { // The CoreText shaper relies on CoreText and CoreText claims @@ -450,17 +468,17 @@ pub const Shaper = struct { const original = face.font; const attrs = try self.features.attrsDict(face.quirks_disable_default_font_features); - cf_release_pool.appendAssumeCapacity(attrs); + self.cf_release_pool.appendAssumeCapacity(attrs); const desc = try macos.text.FontDescriptor.createWithAttributes(attrs); - cf_release_pool.appendAssumeCapacity(desc); + self.cf_release_pool.appendAssumeCapacity(desc); const copied = try original.copyWithAttributes(0, null, desc); errdefer copied.release(); break :font copied; }; - cf_release_pool.appendAssumeCapacity(run_font); + self.cf_release_pool.appendAssumeCapacity(run_font); // Get our font and use that get the attributes to set for the // attributed string so the whole string uses the same font. @@ -500,7 +518,7 @@ pub const Shaper = struct { const pair = macos.foundation.stringGetSurrogatePairForLongCharacter( cp, - state.unichars.items[state.unichars.items.len-2..][0..2], + state.unichars.items[state.unichars.items.len - 2 ..][0..2], ); if (!pair) { state.unichars.items.len -= 1; @@ -599,14 +617,6 @@ test "run iterator: empty cells with background set" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -646,7 +656,7 @@ test "run iterator: empty cells with background set" { ); { const run = (try it.next(alloc)).?; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 3), cells.len); } try testing.expect(try it.next(alloc) == null); @@ -657,14 +667,6 @@ test "shape" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -691,7 +693,7 @@ test "shape" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -700,14 +702,6 @@ test "shape nerd fonts" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaperWithFont(alloc, .nerd_font); defer testdata.deinit(); @@ -734,7 +728,7 @@ test "shape nerd fonts" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -743,14 +737,6 @@ test "shape inconsolata ligs" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -771,7 +757,7 @@ test "shape inconsolata ligs" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 2), cells.len); try testing.expect(cells[0].glyph_index != null); try testing.expect(cells[1].glyph_index == null); @@ -796,7 +782,7 @@ test "shape inconsolata ligs" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 3), cells.len); try testing.expect(cells[0].glyph_index != null); try testing.expect(cells[1].glyph_index == null); @@ -810,14 +796,6 @@ test "shape monaspace ligs" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaperWithFont(alloc, .monaspace_neon); defer testdata.deinit(); @@ -838,7 +816,7 @@ test "shape monaspace ligs" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 3), cells.len); try testing.expect(cells[0].glyph_index != null); try testing.expect(cells[1].glyph_index == null); @@ -853,14 +831,6 @@ test "shape left-replaced lig in last run" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaperWithFont(alloc, .geist_mono); defer testdata.deinit(); @@ -881,7 +851,7 @@ test "shape left-replaced lig in last run" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 3), cells.len); try testing.expect(cells[0].glyph_index != null); try testing.expect(cells[1].glyph_index == null); @@ -896,14 +866,6 @@ test "shape left-replaced lig in early run" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaperWithFont(alloc, .geist_mono); defer testdata.deinit(); @@ -922,7 +884,7 @@ test "shape left-replaced lig in early run" { ); const run = (try it.next(alloc)).?; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 4), cells.len); try testing.expect(cells[0].glyph_index != null); try testing.expect(cells[1].glyph_index == null); @@ -936,14 +898,6 @@ test "shape U+3C9 with JB Mono" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaperWithFont(alloc, .jetbrains_mono); defer testdata.deinit(); @@ -965,7 +919,7 @@ test "shape U+3C9 with JB Mono" { var cell_count: usize = 0; while (try it.next(alloc)) |run| { run_count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); cell_count += cells.len; } try testing.expectEqual(@as(usize, 1), run_count); @@ -977,14 +931,6 @@ test "shape emoji width" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1005,7 +951,7 @@ test "shape emoji width" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 1), cells.len); } try testing.expectEqual(@as(usize, 1), count); @@ -1016,14 +962,6 @@ test "shape emoji width long" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1052,7 +990,7 @@ test "shape emoji width long" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); // screen.testWriteString isn't grapheme aware, otherwise this is one try testing.expectEqual(@as(usize, 5), cells.len); @@ -1064,14 +1002,6 @@ test "shape variation selector VS15" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1097,7 +1027,7 @@ test "shape variation selector VS15" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 1), cells.len); } try testing.expectEqual(@as(usize, 1), count); @@ -1107,14 +1037,6 @@ test "shape variation selector VS16" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1140,7 +1062,7 @@ test "shape variation selector VS16" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 1), cells.len); } try testing.expectEqual(@as(usize, 1), count); @@ -1150,14 +1072,6 @@ test "shape with empty cells in between" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1181,7 +1095,7 @@ test "shape with empty cells in between" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 1), count); try testing.expectEqual(@as(usize, 7), cells.len); } @@ -1191,14 +1105,6 @@ test "shape Chinese characters" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1227,7 +1133,7 @@ test "shape Chinese characters" { while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 4), cells.len); try testing.expectEqual(@as(u16, 0), cells[0].x); try testing.expectEqual(@as(u16, 0), cells[1].x); @@ -1241,14 +1147,6 @@ test "shape box glyphs" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1274,7 +1172,7 @@ test "shape box glyphs" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - const cells = try shaper.shape(run, &cf_release_pool); + const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 2), cells.len); try testing.expectEqual(@as(u32, 0x2500), cells[0].glyph_index.?); try testing.expectEqual(@as(u16, 0), cells[0].x); @@ -1288,14 +1186,6 @@ test "shape selection boundary" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1322,7 +1212,7 @@ test "shape selection boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1345,7 +1235,7 @@ test "shape selection boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1368,7 +1258,7 @@ test "shape selection boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1391,7 +1281,7 @@ test "shape selection boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 3), count); } @@ -1414,7 +1304,7 @@ test "shape selection boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 3), count); } @@ -1424,14 +1314,6 @@ test "shape cursor boundary" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1454,7 +1336,7 @@ test "shape cursor boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1473,7 +1355,7 @@ test "shape cursor boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1492,7 +1374,7 @@ test "shape cursor boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 3), count); } @@ -1511,7 +1393,7 @@ test "shape cursor boundary" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1521,14 +1403,6 @@ test "shape cursor boundary and colored emoji" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1551,7 +1425,7 @@ test "shape cursor boundary and colored emoji" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1570,7 +1444,7 @@ test "shape cursor boundary and colored emoji" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1587,7 +1461,7 @@ test "shape cursor boundary and colored emoji" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1597,14 +1471,6 @@ test "shape cell attribute change" { const testing = std.testing; const alloc = testing.allocator; - var cf_release_pool = std.ArrayList(*anyopaque).init(alloc); - defer { - for (cf_release_pool.items) |ref| { - macos.foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - var testdata = try testShaper(alloc); defer testdata.deinit(); @@ -1625,7 +1491,7 @@ test "shape cell attribute change" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1649,7 +1515,7 @@ test "shape cell attribute change" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1674,7 +1540,7 @@ test "shape cell attribute change" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 2), count); } @@ -1699,7 +1565,7 @@ test "shape cell attribute change" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } @@ -1723,7 +1589,7 @@ test "shape cell attribute change" { var count: usize = 0; while (try it.next(alloc)) |run| { count += 1; - _ = try shaper.shape(run, &cf_release_pool); + _ = try shaper.shape(run); } try testing.expectEqual(@as(usize, 1), count); } diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index f4813fc17..73afdbd6e 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1018,9 +1018,6 @@ pub fn updateFrame( if (critical.preedit) |p| p.deinit(self.alloc); } - var cf_release_pool = std.ArrayList(*anyopaque).init(self.alloc); - try cf_release_pool.ensureTotalCapacity(state.terminal.rows * 8); - // Build our GPU cells try self.rebuildCells( critical.full_rebuild, @@ -1029,27 +1026,23 @@ pub fn updateFrame( critical.preedit, critical.cursor_style, &critical.color_palette, - &cf_release_pool, ); - if (cf_release_pool.items.len > 0) { - const items = try cf_release_pool.toOwnedSlice(); + if (self.font_shaper.cf_release_pool.items.len > 0) { + const alloc = self.font_shaper.alloc; + const items = try self.font_shaper.cf_release_pool.toOwnedSlice(alloc); if (self.cf_release_thread.mailbox.push( .{ .release = .{ .refs = items, - .alloc = self.alloc, + .alloc = alloc, } }, .{ .forever = {} }, ) != 0) { try self.cf_release_thread.wakeup.notify(); } else { - for (items) |ref| { - macos.foundation.CFRelease(ref); - } - self.alloc.free(items); + for (items) |ref| macos.foundation.CFRelease(ref); + alloc.free(items); } - } else { - cf_release_pool.deinit(); } // Update our viewport pin @@ -1931,7 +1924,6 @@ fn rebuildCells( preedit: ?renderer.State.Preedit, cursor_style_: ?renderer.CursorStyle, color_palette: *const terminal.color.Palette, - cf_release_pool: *std.ArrayList(*anyopaque), ) !void { // const start = try std.time.Instant.now(); // const start_micro = std.time.microTimestamp(); @@ -2013,10 +2005,7 @@ fn rebuildCells( while (try iter.next(self.alloc)) |run| { // Try to read the cells from the shaping cache if we can. const shaper_cells = self.font_shaper_cache.get(run) orelse cache: { - const cells = if (font.options.backend == .coretext) - try self.font_shaper.shape(run, cf_release_pool) - else - try self.font_shaper.shape(run); + const cells = try self.font_shaper.shape(run); // Try to cache them. If caching fails for any reason we continue // because it is just a performance optimization, not a correctness diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 5dd8d9345..8389dbae6 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1025,16 +1025,7 @@ pub fn rebuildCells( while (try iter.next(self.alloc)) |run| { // Try to read the cells from the shaping cache if we can. const shaper_cells = self.font_shaper_cache.get(run) orelse cache: { - const cells = if (font.options.backend == .coretext) ct: { - var cf_release_pool = std.ArrayList(*anyopaque).init(self.alloc); - defer { - for (cf_release_pool.items) |ref| { - @import("macos").foundation.CFRelease(ref); - } - cf_release_pool.deinit(); - } - break :ct try self.font_shaper.shape(run, &cf_release_pool); - } else try self.font_shaper.shape(run); + const cells = try self.font_shaper.shape(run); // Try to cache them. If caching fails for any reason we continue // because it is just a performance optimization, not a correctness