diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/p4.zig | 51 |
1 files changed, 38 insertions, 13 deletions
@@ -207,19 +207,39 @@ var in_paste: bool = false; /// starves input. var dirty: bool = true; -/// The largest grid this board can render, and the reason it is not the host's terminal size. +/// The largest grid this board can render, and the reason it is not just the host's terminal size. /// -/// Every cell is paid for four times over: vaxis keeps a `Screen` and an `InternalScreen`, pardes -/// keeps its own `Surface` and `previous_cells`. Against a 384 KiB heap that puts a hard ceiling on -/// the geometry, and it was measured rather than guessed - 40x12 initialises with room to spare, -/// 80x24 exhausts the heap and `Pardes.init` returns OutOfMemory with 9,128 bytes left. +/// A cell is paid for TWICE now, not four times: pardes keeps its `Surface` and this shell keeps a +/// shadow copy of it to diff against. vaxis used to keep a `Screen` and an `InternalScreen` as well, +/// and with `direct_emit` neither is ever read - the emitter diffs against the Surface and writes +/// the wire itself - so `init` sizes vaxis to a single cell and those two grids cost nothing. /// -/// Raising these is what PSRAM would buy: this board has 32 MB fitted and untrained. -pub const max_cols: u16 = 40; -pub const max_rows: u16 = 12; +/// Set with `-Dp4-cols` / `-Dp4-rows`, because the ceiling is a measurement rather than a constant +/// and it moves for two independent reasons: the 384 KiB heap, and the round trip, which grows with +/// the cell count because every frame walks the whole grid. See the geometry table in +/// `05-zig-p4/experiments/report.typ` for both curves. +/// +/// Raising these further is what PSRAM would buy: this board has 32 MB fitted and untrained. +pub const max_cols: u16 = @import("pardes_config").p4_cols; +pub const max_rows: u16 = @import("pardes_config").p4_rows; var cur_winsize: vaxis.Winsize = .{ .rows = max_rows, .cols = max_cols, .x_pixel = 0, .y_pixel = 0 }; +/// How big vaxis's own grids need to be. +/// +/// ONE CELL under `direct_emit`, because neither of them is ever read: vaxis keeps a `Screen` and an +/// `InternalScreen`, and the emitter diffs the Surface against its own shadow and writes the escapes +/// itself. Those two grids were the largest single claim on a 384 KiB heap and the reason the board +/// was held to 40x12 - the comment above `max_cols` used to say a cell was paid for four times over, +/// and this is what took it down to two. vaxis is still doing the work only it can do here: entering +/// the alternate screen, asking the terminal what it is, and parsing everything that comes back. +fn vaxisSize() vaxis.Winsize { + return if (direct_emit) + .{ .rows = 1, .cols = 1, .x_pixel = 0, .y_pixel = 0 } + else + cur_winsize; +} + // -------------------------------------------------------------------------------------- exports /// Hand over the allocator and the output sink, state the initial window size, and bring the editor @@ -253,7 +273,7 @@ export fn pardes_p4_init( pardes.syntax.start(allocs.tree_sitter); vx = vaxis.init(std.Io.failing, a, &env_map, .{}) catch |err| return errCode(err); - vx.resize(a, &out, cur_winsize) catch |err| return errCode(err); + vx.resize(a, &out, vaxisSize()) catch |err| return errCode(err); // Ask the terminal what it is. Both halves are pure byte writers, which is the whole reason this // works over a serial line: the replies arrive as ordinary input and are parsed like any key. @@ -452,10 +472,15 @@ fn apply(c: *pardes.Pardes, ev: vaxis.Event) void { }; if (want.cols == cur_winsize.cols and want.rows == cur_winsize.rows) return; const previous = cur_winsize; - vx.resize(gpa(), &out, want) catch { - vx.resize(gpa(), &out, previous) catch {}; - return; - }; + // vaxis is only resized when it is the thing doing the rendering. Under `direct_emit` its + // grids are a single cell and stay that way - see `vaxisSize` - so there is nothing here + // to reallocate, which also means a resize can no longer fail for want of two grids. + if (!direct_emit) { + vx.resize(gpa(), &out, want) catch { + vx.resize(gpa(), &out, previous) catch {}; + return; + }; + } cur_winsize = want; c.update(.{ .resize = .{ .cols = want.cols, .rows = want.rows } }); dirty = true; |
