From 5de88fe3f8faba3542e70ace993ce28263f984a7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 1 Apr 2024 15:43:43 -0700 Subject: [PATCH] core: deref the font group when not used --- src/Surface.zig | 10 +++++++++- src/font/GroupCacheSet.zig | 28 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index c8cf55ebc..00258e112 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -54,6 +54,7 @@ rt_app: *apprt.runtime.App, rt_surface: *apprt.runtime.Surface, /// The font structures +font_group_key: font.GroupCacheSet.Key, font_size: font.face.DesiredSize, /// The renderer for this surface. @@ -320,7 +321,10 @@ pub fn init( // Setup our font group. This will reuse an existing font group if // it was already loaded. - const font_group = try app.font_group_set.groupInit(config, font_size); + const font_group_key, const font_group = try app.font_group_set.groupRef( + config, + font_size, + ); // Pre-calculate our initial cell size ourselves. const cell_size = try renderer.CellSize.init(alloc, font_group); @@ -406,6 +410,7 @@ pub fn init( .app = app, .rt_app = rt_app, .rt_surface = rt_surface, + .font_group_key = font_group_key, .font_size = font_size, .renderer = renderer_impl, .renderer_thread = render_thread, @@ -525,6 +530,9 @@ pub fn deinit(self: *Surface) void { self.alloc.destroy(v); } + // Clean up our font group + self.app.font_group_set.groupDeref(self.font_group_key); + // Clean up our render state if (self.renderer_state.preedit) |p| self.alloc.free(p.codepoints); self.alloc.destroy(self.renderer_state.mutex); diff --git a/src/font/GroupCacheSet.zig b/src/font/GroupCacheSet.zig index bab0eae3f..4ab97ce02 100644 --- a/src/font/GroupCacheSet.zig +++ b/src/font/GroupCacheSet.zig @@ -61,6 +61,7 @@ pub fn init(alloc: Allocator) !GroupCacheSet { pub fn deinit(self: *GroupCacheSet) void { var it = self.map.iterator(); while (it.next()) |entry| { + entry.key_ptr.deinit(); const ref = entry.value_ptr.*; ref.cache.deinit(self.alloc); self.alloc.destroy(ref.cache); @@ -79,11 +80,11 @@ pub fn deinit(self: *GroupCacheSet) void { /// 1. If it is present, the ref count will be incremented. /// /// This is NOT thread-safe. -pub fn groupInit( +pub fn groupRef( self: *GroupCacheSet, config: *const Config, font_size: DesiredSize, -) !*GroupCache { +) !struct { Key, *GroupCache } { var key = try Key.init(self.alloc, config); errdefer key.deinit(); @@ -94,7 +95,7 @@ pub fn groupInit( // Increment our ref count and return the cache gop.value_ptr.ref += 1; - return gop.value_ptr.cache; + return .{ gop.key_ptr.*, gop.value_ptr.cache }; } errdefer self.map.removeByPtr(gop.key_ptr); @@ -210,7 +211,26 @@ pub fn groupInit( }); errdefer cache.deinit(self.alloc); - return gop.value_ptr.cache; + return .{ gop.key_ptr.*, gop.value_ptr.cache }; +} + +/// Decrement the ref count for the given key. If the ref count is zero, +/// the GroupCache will be deinitialized and removed from the map.j:w +pub fn groupDeref(self: *GroupCacheSet, key: Key) void { + const entry = self.map.getEntry(key) orelse return; + assert(entry.value_ptr.ref >= 1); + + // If we have more than one reference, decrement and return. + if (entry.value_ptr.ref > 1) { + entry.value_ptr.ref -= 1; + return; + } + + // We are at a zero ref count so deinit the group and remove. + entry.key_ptr.deinit(); + entry.value_ptr.cache.deinit(self.alloc); + self.alloc.destroy(entry.value_ptr.cache); + self.map.removeByPtr(entry.key_ptr); } /// Map of font configurations to GroupCache instances. The GroupCache