From 8b23e73d203d975811e9a97f33092b9221c86ba5 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Fri, 20 Jun 2025 14:28:31 -0600 Subject: [PATCH] metal: retain IOSurfaceLayer ourselves instead of relying on the view If this was Swift code, we'd be using a strong reference, which would retain the layer for us and release it when the object is deallocated, but this is Zig land so we have to do that manually. NOTE: We don't *have* to do this, but it fits much better with Zig idiom and hopefully avoids potential future footguns. We should do this to any autoreleased objects that we persist a reference to in a Zig struct. --- src/renderer/Metal.zig | 4 +--- src/renderer/metal/IOSurfaceLayer.zig | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 766cbefa5..94c087f6c 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -165,9 +165,7 @@ pub fn init(alloc: Allocator, opts: rendererpkg.Options) !Metal { pub fn deinit(self: *Metal) void { self.queue.release(); self.device.release(); - - // NOTE: We don't release the layer here because that should be taken - // care of automatically when the hosting view is destroyed. + self.layer.release(); } pub fn loopEnter(self: *Metal) void { diff --git a/src/renderer/metal/IOSurfaceLayer.zig b/src/renderer/metal/IOSurfaceLayer.zig index 4c51a55c2..9212bd5e1 100644 --- a/src/renderer/metal/IOSurfaceLayer.zig +++ b/src/renderer/metal/IOSurfaceLayer.zig @@ -21,11 +21,14 @@ var Subclass: ?objc.Class = null; layer: objc.Object, pub fn init() !IOSurfaceLayer { + // The layer returned by `[CALayer layer]` is autoreleased, which means + // that at the end of the current autorelease pool it will be deallocated + // if it isn't retained, so we retain it here manually an extra time. const layer = (try getSubclass()).msgSend( objc.Object, objc.sel("layer"), .{}, - ); + ).retain(); errdefer layer.release(); // The layer gravity is set to top-left so that the contents aren't