console: page-wrap instead of scrolling — never read the framebuffer

The scroll path copied every pixel row up by one glyph height, READING
video memory — and VRAM reads are uncached-slow on real hardware.
Measured on the 16-core PC: ~90 seconds to bring the cores online,
almost entirely boot-transcript lines each paying a whole-screen scroll
copy. (QEMU never shows this: its 'VRAM' is host RAM.)

When the screen fills, the console now clears and restarts at the top —
writes only, once per screenful. The transcript reads the same as it
streams; only the scrollback illusion is gone, which a boot console
never needed.
This commit is contained in:
Daniel Samson
2026-07-21 19:22:59 +01:00
parent b541921218
commit f587e7e05e
+6 -10
View File
@@ -138,14 +138,16 @@ pub const Console = struct {
} }
} }
/// Shift the visible text up one glyph row and clear the freed bottom row, /// The screen is full: start a fresh page at the top. NEVER scroll by
/// leaving the cursor on that now-blank last line. /// copying pixel rows — that READS the framebuffer, and VRAM reads are
/// uncached-slow on real hardware (measured: 16-core bring-up took ~90 s
/// purely from boot lines each paying a whole-screen scroll copy). A page
/// clear is writes only, and only once per screenful.
fn scroll(self: *Console) void { fn scroll(self: *Console) void {
const visible = self.rows * glyph_h; const visible = self.rows * glyph_h;
var y: u32 = 0; var y: u32 = 0;
while (y + glyph_h < visible) : (y += 1) self.copyRow(y, y + glyph_h);
while (y < visible) : (y += 1) self.fillRow(y, self.bg); while (y < visible) : (y += 1) self.fillRow(y, self.bg);
self.row = self.rows - 1; self.row = 0;
} }
inline fn rowPtr(self: *Console, y: u32) [*]volatile u32 { inline fn rowPtr(self: *Console, y: u32) [*]volatile u32 {
@@ -163,10 +165,4 @@ pub const Console = struct {
while (x < self.fb.width) : (x += 1) row[x] = color; while (x < self.fb.width) : (x += 1) row[x] = color;
} }
fn copyRow(self: *Console, destination_y: u32, source_y: u32) void {
const destination = self.rowPtr(destination_y);
const source = self.rowPtr(source_y);
var x: u32 = 0;
while (x < self.fb.width) : (x += 1) destination[x] = source[x];
}
}; };