renderer/Metal: only rebuild rows that are dirty

This commit is contained in:
Mitchell Hashimoto
2024-04-28 14:16:20 -07:00
parent 7e52f94278
commit b166ca7e30

View File

@ -92,6 +92,9 @@ current_background_color: terminal.color.RGB,
/// cells goes into a separate shader.
cells: mtl_cell.Contents,
/// If this is true, we do a full cell rebuild on the next frame.
cells_rebuild: bool = true,
/// The current GPU uniform values.
uniforms: mtl_shaders.Uniforms,
@ -786,6 +789,31 @@ pub fn updateFrame(
try self.prepKittyGraphics(state.terminal);
}
// If we have any terminal dirty flags set then we need to rebuild
// the entire screen. This can be optimized in the future.
{
const Int = @typeInfo(terminal.Terminal.Dirty).Struct.backing_integer.?;
const v: Int = @bitCast(state.terminal.flags.dirty);
if (v > 0) self.cells_rebuild = true;
}
// Reset the dirty flags in the terminal and screen. We assume
// that our rebuild will be successful since so we optimize for
// success and reset while we hold the lock. This is much easier
// than coordinating row by row or as changes are persisted.
state.terminal.flags.dirty = .{};
{
var it = state.terminal.screen.pages.pageIterator(
.right_down,
.{ .screen = .{} },
null,
);
while (it.next()) |chunk| {
var dirty_set = chunk.page.data.dirtyBitSet();
dirty_set.unsetAll();
}
}
break :critical .{
.bg = self.background_color,
.screen = screen_copy,
@ -1711,6 +1739,10 @@ fn rebuildCells(
while (row_it.next()) |row| {
y = y - 1;
// Only rebuild if we are doing a full rebuild or this row is dirty.
// if (row.isDirty()) std.log.warn("dirty y={}", .{y});
if (!self.cells_rebuild and !row.isDirty()) continue;
// If we're rebuilding a row, then we always clear the cells
self.cells.clear(y);
@ -1856,6 +1888,9 @@ fn rebuildCells(
}
}
// We always mark our rebuild flag as false since we're done.
self.cells_rebuild = false;
// Log some things
// log.debug("rebuildCells complete cached_runs={}", .{
// self.font_shaper_cache.count(),