7a8bf92e
Add render cache data structures
a73x 2026-04-08 18:52
diff --git a/src/main.zig b/src/main.zig index 39c40e4..5455e3c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -719,6 +719,56 @@ test "repackRowCaches keeps cursor span explicit for empty and non-empty cursor try std.testing.expectEqualDeep([2]f32{ 9.0, 10.0 }, packed_instances.items[2].cell_pos); } test "RenderCache resizeRows preserves surviving row caches" { var cache = RenderCache.empty; defer cache.deinit(std.testing.allocator); try cache.resizeRows(std.testing.allocator, 2); cache.rows[0].instances = try makeTestInstances(std.testing.allocator, 1); cache.rows[0].gpu_offset_instances = 17; cache.rows[0].gpu_len_instances = 1; try cache.resizeRows(std.testing.allocator, 3); try std.testing.expectEqual(@as(usize, 3), cache.rows.len); try std.testing.expectEqual(@as(usize, 1), cache.rows[0].instances.items.len); try std.testing.expectEqual(@as(u32, 17), cache.rows[0].gpu_offset_instances); try std.testing.expectEqual(@as(u32, 1), cache.rows[0].gpu_len_instances); try std.testing.expectEqual(@as(usize, 0), cache.rows[2].instances.items.len); try cache.resizeRows(std.testing.allocator, 1); try std.testing.expectEqual(@as(usize, 1), cache.rows.len); try std.testing.expectEqual(@as(usize, 1), cache.rows[0].instances.items.len); try std.testing.expectEqual(@as(u32, 17), cache.rows[0].gpu_offset_instances); try std.testing.expectEqual(@as(u32, 1), cache.rows[0].gpu_len_instances); } test "RenderCache deinit resets fields after releasing row storage" { var cache = RenderCache.empty; try cache.resizeRows(std.testing.allocator, 2); cache.rows[0].instances = try makeTestInstances(std.testing.allocator, 2); cache.rows[1].instances = try makeTestInstances(std.testing.allocator, 1); var cursor_instances = try makeTestInstances(std.testing.allocator, 1); defer cursor_instances.deinit(std.testing.allocator); try cache.cursor_instances.append(std.testing.allocator, cursor_instances.items[0]); var packed_instances = try makeTestInstances(std.testing.allocator, 1); defer packed_instances.deinit(std.testing.allocator); try cache.packed_instances.append(std.testing.allocator, packed_instances.items[0]); cache.total_instance_count = 3; cache.layout_dirty = false; cache.deinit(std.testing.allocator); try std.testing.expectEqual(@as(usize, 0), cache.rows.len); try std.testing.expectEqual(@as(usize, 0), cache.cursor_instances.items.len); try std.testing.expectEqual(@as(usize, 0), cache.packed_instances.items.len); try std.testing.expectEqual(@as(u32, 0), cache.total_instance_count); try std.testing.expect(cache.layout_dirty); } const RowInstanceCache = struct { instances: std.ArrayListUnmanaged(renderer.Instance) = .empty, gpu_offset_instances: u32 = 0, @@ -726,6 +776,65 @@ const RowInstanceCache = struct { fn deinit(self: *RowInstanceCache, alloc: std.mem.Allocator) void { self.instances.deinit(alloc); self.* = .{}; } }; const RenderCache = struct { rows: []RowInstanceCache = &.{}, cursor_instances: std.ArrayListUnmanaged(renderer.Instance) = .empty, packed_instances: std.ArrayListUnmanaged(renderer.Instance) = .empty, total_instance_count: u32 = 0, layout_dirty: bool = true, const empty: RenderCache = .{}; fn resizeRows(self: *RenderCache, alloc: std.mem.Allocator, row_count: usize) !void { if (self.rows.len == row_count) return; if (row_count == 0) { const old_rows = self.rows; if (old_rows.len > 0) { var row_idx: usize = 0; while (row_idx < old_rows.len) : (row_idx += 1) { old_rows[row_idx].deinit(alloc); } alloc.free(old_rows); } self.rows = &.{}; return; } const old_rows = self.rows; var new_rows = try alloc.alloc(RowInstanceCache, row_count); for (new_rows) |*row| row.* = .{}; const copy_len = @min(old_rows.len, row_count); if (copy_len > 0) { @memcpy(new_rows[0..copy_len], old_rows[0..copy_len]); } if (row_count < old_rows.len) { var row_idx = row_count; while (row_idx < old_rows.len) : (row_idx += 1) { old_rows[row_idx].deinit(alloc); } } if (old_rows.len > 0) { alloc.free(old_rows); } self.rows = new_rows; } fn deinit(self: *RenderCache, alloc: std.mem.Allocator) void { for (self.rows) |*row| row.deinit(alloc); if (self.rows.len > 0) { alloc.free(self.rows); } self.cursor_instances.deinit(alloc); self.packed_instances.deinit(alloc); self.* = .{}; } };