mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
Only reallocate the GPU buffer if our CPU capacity changes
Previously, every single render was re-allocating a fairly large (~1MB) buffer on the GPU. The recommended best practice is to allocate once and then use `glBufferSubData` to update the memory in-place on the GPU. We now track the last size we sent to the GPU, compare it to our copy on the CPU, and if it _grows_ then we reallocate the GPU buffer. If it shrinks we leave the GPU as-is for now. After this, we use the sub-data routines to update the data in place.
This commit is contained in:
27
src/Grid.zig
27
src/Grid.zig
@ -27,6 +27,11 @@ cell_size: CellSize,
|
||||
/// The current set of cells to render.
|
||||
cells: std.ArrayListUnmanaged(GPUCell),
|
||||
|
||||
/// The size of the cells list that was sent to the GPU. This is used
|
||||
/// to detect when the cells array was reallocated/resized and handle that
|
||||
/// accordingly.
|
||||
gl_cells_size: usize = 0,
|
||||
|
||||
/// Shader program for cell rendering.
|
||||
program: gl.Program,
|
||||
vao: gl.VertexArray,
|
||||
@ -497,7 +502,7 @@ pub fn flushAtlas(self: *Grid) !void {
|
||||
self.atlas_dirty = false;
|
||||
}
|
||||
|
||||
pub fn render(self: Grid) !void {
|
||||
pub fn render(self: *Grid) !void {
|
||||
const t = trace(@src());
|
||||
defer t.end();
|
||||
|
||||
@ -518,7 +523,25 @@ pub fn render(self: Grid) !void {
|
||||
// Bind VBO and set data
|
||||
var binding = try self.vbo.bind(.ArrayBuffer);
|
||||
defer binding.unbind();
|
||||
try binding.setData(self.cells.items, .StaticDraw);
|
||||
|
||||
// Our allocated buffer on the GPU is smaller than our capacity.
|
||||
// We reallocate a new buffer with the full new capacity.
|
||||
if (self.gl_cells_size < self.cells.capacity) {
|
||||
log.info("reallocating GPU buffer old={} new={}", .{
|
||||
self.gl_cells_size,
|
||||
self.cells.capacity,
|
||||
});
|
||||
|
||||
try binding.setDataNullManual(
|
||||
@sizeOf(GPUCell) * self.cells.capacity,
|
||||
.StaticDraw,
|
||||
);
|
||||
self.gl_cells_size = self.cells.capacity;
|
||||
}
|
||||
|
||||
// We always set the data using subdata if possible to avoid reallocation
|
||||
// on the GPU.
|
||||
try binding.setSubData(0, self.cells.items);
|
||||
|
||||
// Bind our texture
|
||||
try gl.Texture.active(gl.c.GL_TEXTURE0);
|
||||
|
@ -69,6 +69,16 @@ pub const Binding = struct {
|
||||
try errors.getError();
|
||||
}
|
||||
|
||||
/// Same as setDataNull but lets you manually specify the buffer size.
|
||||
pub inline fn setDataNullManual(
|
||||
b: Binding,
|
||||
size: usize,
|
||||
usage: Usage,
|
||||
) !void {
|
||||
c.glBufferData(@enumToInt(b.target), @intCast(c_long, size), null, @enumToInt(usage));
|
||||
try errors.getError();
|
||||
}
|
||||
|
||||
fn dataInfo(data: anytype) struct {
|
||||
size: isize,
|
||||
ptr: *const anyopaque,
|
||||
|
Reference in New Issue
Block a user