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.
This commit is contained in:
Uzair Aftab
2026-07-27 20:24:34 +02:00
parent 2dd79f3bc6
commit 4a22eed6d9

View File

@@ -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,
},
);