From 4a22eed6d9e054fc162a1fb8d4b2899f144da174 Mon Sep 17 00:00:00 2001 From: Uzair Aftab Date: Mon, 27 Jul 2026 20:24:34 +0200 Subject: [PATCH] renderer/metal: fix 2x sizeof over-allocation in Buffer.sync Buffer.sync and Buffer.syncFromArrayLists computed the new buffer size in bytes (req_bytes * 2) and then multiplied by @sizeOf(T) again when passing it to newBufferWithLength:, allocating data.len * sizeOf(T)^2 * 2 bytes. For the 32-byte CellText buffers this is a 64x over-allocation and for the 4-byte CellBg buffers 8x, per swap-chain frame (e.g. ~9.4MB instead of ~300KB per frame for a full 120x40 screen of text). Match the OpenGL buffer implementation: track the new length in units of T and multiply by @sizeOf(T) exactly once. --- src/renderer/metal/buffer.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/metal/buffer.zig b/src/renderer/metal/buffer.zig index f91f89e99..d892da2ab 100644 --- a/src/renderer/metal/buffer.zig +++ b/src/renderer/metal/buffer.zig @@ -81,12 +81,12 @@ pub fn Buffer(comptime T: type) type { self.buffer.msgSend(void, objc.sel("release"), .{}); // Allocate a new buffer with enough to hold double what we require. - const size = req_bytes * 2; + self.len = data.len * 2; self.buffer = self.opts.device.msgSend( objc.Object, objc.sel("newBufferWithLength:options:"), .{ - @as(c_ulong, @intCast(size * @sizeOf(T))), + @as(c_ulong, @intCast(self.len * @sizeOf(T))), self.opts.resource_options, }, ); @@ -138,12 +138,12 @@ pub fn Buffer(comptime T: type) type { self.buffer.msgSend(void, objc.sel("release"), .{}); // Allocate a new buffer with enough to hold double what we require. - const size = req_bytes * 2; + self.len = total_len * 2; self.buffer = self.opts.device.msgSend( objc.Object, objc.sel("newBufferWithLength:options:"), .{ - @as(c_ulong, @intCast(size * @sizeOf(T))), + @as(c_ulong, @intCast(self.len * @sizeOf(T))), self.opts.resource_options, }, );