aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/renderer/opengl/buffer.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/renderer/opengl/buffer.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/renderer/opengl/buffer.zig')
-rw-r--r--vendor/libghostty-vt/src/renderer/opengl/buffer.zig126
1 files changed, 126 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/renderer/opengl/buffer.zig b/vendor/libghostty-vt/src/renderer/opengl/buffer.zig
new file mode 100644
index 00000000..f9cbbceb
--- /dev/null
+++ b/vendor/libghostty-vt/src/renderer/opengl/buffer.zig
@@ -0,0 +1,126 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const gl = @import("opengl");
+
+const OpenGL = @import("../OpenGL.zig");
+
+const log = std.log.scoped(.opengl);
+
+/// Options for initializing a buffer.
+pub const Options = struct {
+ target: gl.Buffer.Target = .array,
+ usage: gl.Buffer.Usage = .dynamic_draw,
+};
+
+/// OpenGL data storage for a certain set of equal types. This is usually
+/// used for vertex buffers, etc. This helpful wrapper makes it easy to
+/// prealloc, shrink, grow, sync, buffers with OpenGL.
+pub fn Buffer(comptime T: type) type {
+ return struct {
+ const Self = @This();
+
+ /// Underlying `gl.Buffer` instance.
+ buffer: gl.Buffer,
+
+ /// Options this buffer was allocated with.
+ opts: Options,
+
+ /// Current allocated length of the data store.
+ /// Note this is the number of `T`s, not the size in bytes.
+ len: usize,
+
+ /// Initialize a buffer with the given length pre-allocated.
+ pub fn init(opts: Options, len: usize) !Self {
+ const buffer = try gl.Buffer.create();
+ errdefer buffer.destroy();
+
+ const binding = try buffer.bind(opts.target);
+ defer binding.unbind();
+
+ try binding.setDataNullManual(len * @sizeOf(T), opts.usage);
+
+ return .{
+ .buffer = buffer,
+ .opts = opts,
+ .len = len,
+ };
+ }
+
+ /// Init the buffer filled with the given data.
+ pub fn initFill(opts: Options, data: []const T) !Self {
+ const buffer = try gl.Buffer.create();
+ errdefer buffer.destroy();
+
+ const binding = try buffer.bind(opts.target);
+ defer binding.unbind();
+
+ try binding.setData(data, opts.usage);
+
+ return .{
+ .buffer = buffer,
+ .opts = opts,
+ .len = data.len * @sizeOf(T),
+ };
+ }
+
+ pub fn deinit(self: Self) void {
+ self.buffer.destroy();
+ }
+
+ /// Sync new contents to the buffer. The data is expected to be the
+ /// complete contents of the buffer. If the amount of data is larger
+ /// than the buffer length, the buffer will be reallocated.
+ ///
+ /// If the amount of data is smaller than the buffer length, the
+ /// remaining data in the buffer is left untouched.
+ pub fn sync(self: *Self, data: []const T) !void {
+ const binding = try self.buffer.bind(self.opts.target);
+ defer binding.unbind();
+
+ // If we need more space than our buffer has, we need to reallocate.
+ if (data.len > self.len) {
+ // Reallocate the buffer to hold double what we require.
+ self.len = data.len * 2;
+ try binding.setDataNullManual(
+ self.len * @sizeOf(T),
+ self.opts.usage,
+ );
+ }
+
+ // We can fit within the buffer so we can just replace bytes.
+ try binding.setSubData(0, data);
+ }
+
+ /// Like Buffer.sync but takes data from an array of ArrayLists,
+ /// rather than a single array. Returns the number of items synced.
+ pub fn syncFromArrayLists(self: *Self, lists: []const std.ArrayListUnmanaged(T)) !usize {
+ const binding = try self.buffer.bind(self.opts.target);
+ defer binding.unbind();
+
+ var total_len: usize = 0;
+ for (lists) |list| {
+ total_len += list.items.len;
+ }
+
+ // If we need more space than our buffer has, we need to reallocate.
+ if (total_len > self.len) {
+ // Reallocate the buffer to hold double what we require.
+ self.len = total_len * 2;
+ try binding.setDataNullManual(
+ self.len * @sizeOf(T),
+ self.opts.usage,
+ );
+ }
+
+ // We can fit within the buffer so we can just replace bytes.
+ var i: usize = 0;
+
+ for (lists) |list| {
+ try binding.setSubData(i, list.items);
+ i += list.items.len * @sizeOf(T);
+ }
+
+ return total_len;
+ }
+ };
+}