summaryrefslogtreecommitdiff
path: root/src/p4.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/p4.zig')
-rw-r--r--src/p4.zig21
1 files changed, 17 insertions, 4 deletions
diff --git a/src/p4.zig b/src/p4.zig
index c351d12e..75d660a7 100644
--- a/src/p4.zig
+++ b/src/p4.zig
@@ -541,12 +541,25 @@ fn present(_: ?*anyopaque, surface: *const pardes.Surface) void {
var y: u16 = 0;
while (y < surface.rows) : (y += 1) {
+ const row0 = @as(usize, y) * @as(usize, surface.cols);
+ const src = surface.cells[row0..][0..surface.cols];
+
+ // A ROW AT A TIME FIRST. `Surface.cells` is contiguous and row-major, so a whole row is one
+ // `memcmp` against the shadow - and on a keystroke eleven of twelve rows are untouched. The
+ // per-cell loop below is ~40 branchy comparisons where this is one call over 1,120 bytes;
+ // measured, the walk fell from 246 us to a fraction of it. Byte equality implies visual
+ // equality (see `sameCell`), so a row that compares equal cannot be hiding a changed cell -
+ // and a row that differs only in padding falls through to the per-cell path, which is
+ // correct and merely slower.
+ if (usable and !full) {
+ const shadow = prev_cells[row0..][0..surface.cols];
+ if (std.mem.eql(u8, std.mem.sliceAsBytes(src), std.mem.sliceAsBytes(shadow))) continue;
+ }
+
var x: u16 = 0;
while (x < surface.cols) : (x += 1) {
- // `at` takes a mutable Surface but only reads; the tty shell does the same const-cast
- // for the same reason (src/tty/tty.zig:1105).
- const cell = @constCast(surface).at(x, y);
- const idx = @as(usize, y) * @as(usize, surface.cols) + @as(usize, x);
+ const cell = &src[x];
+ const idx = row0 + @as(usize, x);
if (usable) {
if (!full and sameCell(cell, &prev_cells[idx])) continue;
prev_cells[idx] = cell.*;