perf: fast display (row runs, bulk fills, pixel scroll), terminal draws changed cells only + scrolls pixels, print! batched (was IPC per fmt fragment), snake sleeps on timer
This commit is contained in:
@@ -10,6 +10,7 @@ pub struct MockFramebuffer {
|
||||
pixels: [(ScreenCoord, ScreenCoord, Color); 4096],
|
||||
pixel_count: usize,
|
||||
flushed: bool,
|
||||
scrolls: usize,
|
||||
}
|
||||
|
||||
impl MockFramebuffer {
|
||||
@@ -20,6 +21,7 @@ impl MockFramebuffer {
|
||||
pixels: [(ScreenCoord::new(0), ScreenCoord::new(0), Color::from_raw(0)); 4096],
|
||||
pixel_count: 0,
|
||||
flushed: false,
|
||||
scrolls: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +29,11 @@ impl MockFramebuffer {
|
||||
self.pixel_count
|
||||
}
|
||||
|
||||
/// How many times the screen was scrolled.
|
||||
pub fn scrolls(&self) -> usize {
|
||||
self.scrolls
|
||||
}
|
||||
|
||||
pub fn was_flushed(&self) -> bool {
|
||||
self.flushed
|
||||
}
|
||||
@@ -62,4 +69,8 @@ impl Framebuffer for MockFramebuffer {
|
||||
fn flush(&mut self) {
|
||||
self.flushed = true;
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self, _top: ScreenCoord, _height: Dimension, _by: Dimension, _fill: Color) {
|
||||
self.scrolls += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ const VQUEUE_VA: VirtualAddress = VirtualAddress::from_raw(0x21000);
|
||||
const CMDBUF_VA: VirtualAddress = VirtualAddress::from_raw(0x23000);
|
||||
const FB_VA: VirtualAddress = VirtualAddress::from_raw(0x100000);
|
||||
const FB_BPP: usize = 4;
|
||||
/// Pixels converted and stored per run.
|
||||
const RUN: usize = 64;
|
||||
const RESOURCE_ID: u32 = 1;
|
||||
/// When the device will not say.
|
||||
const DEFAULT_SIZE: (u16, u16) = (640, 480);
|
||||
@@ -79,6 +81,12 @@ impl VirtioFramebuffer {
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioFramebuffer {
|
||||
fn pixel(&self, x: usize, y: usize) -> ByteOffset {
|
||||
ByteOffset::new(y * self.stride + x * FB_BPP)
|
||||
}
|
||||
}
|
||||
|
||||
impl Framebuffer for VirtioFramebuffer {
|
||||
fn width(&self) -> Dimension {
|
||||
self.width
|
||||
@@ -89,18 +97,33 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
}
|
||||
|
||||
fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) {
|
||||
if x.raw() >= self.width.raw() || y.raw() >= self.height.raw() {
|
||||
return;
|
||||
}
|
||||
let offset = (y.raw() as usize) * self.stride + (x.raw() as usize) * FB_BPP;
|
||||
self.pixels.write(ByteOffset::new(offset), color.raw());
|
||||
self.write_row(x, y, &[color]);
|
||||
}
|
||||
|
||||
fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
|
||||
for dy in 0..h.raw() {
|
||||
for dx in 0..w.raw() {
|
||||
self.write_pixel(ScreenCoord::new(x.raw() + dx), ScreenCoord::new(y.raw() + dy), color);
|
||||
fn write_row(&mut self, x: ScreenCoord, y: ScreenCoord, pixels: &[Color]) {
|
||||
let (w, h) = (self.width.raw() as usize, self.height.raw() as usize);
|
||||
let (x, y) = (x.raw() as usize, y.raw() as usize);
|
||||
if x >= w || y >= h {
|
||||
return;
|
||||
}
|
||||
let mut run = [0u32; RUN];
|
||||
let mut at = self.pixel(x, y);
|
||||
for chunk in pixels[..pixels.len().min(w - x)].chunks(RUN) {
|
||||
for (slot, c) in run.iter_mut().zip(chunk) {
|
||||
*slot = c.raw();
|
||||
}
|
||||
self.pixels.write_u32s(at, &run[..chunk.len()]);
|
||||
at = at + chunk.len() * FB_BPP;
|
||||
}
|
||||
}
|
||||
|
||||
/// Callers clip to the screen (the display server does).
|
||||
fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
|
||||
let (fw, fh) = (self.width.raw() as usize, self.height.raw() as usize);
|
||||
let (x, y) = (x.raw() as usize, y.raw() as usize);
|
||||
let w = (w.raw() as usize).min(fw.saturating_sub(x));
|
||||
for row in y..(y + h.raw() as usize).min(fh) {
|
||||
self.pixels.fill_u32(self.pixel(x, row), w, color.raw());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +132,17 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
self.pixels.fill_u32(ByteOffset::ZERO, total, color.raw());
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self, top: ScreenCoord, height: Dimension, by: Dimension, fill: Color) {
|
||||
let fh = self.height.raw() as usize;
|
||||
let top = top.raw() as usize;
|
||||
let bottom = (top + height.raw() as usize).min(fh);
|
||||
let by = (by.raw() as usize).min(bottom.saturating_sub(top));
|
||||
let moved = bottom - top - by;
|
||||
self.pixels.copy_within(self.pixel(0, top + by), self.pixel(0, top), moved * self.stride);
|
||||
let width = self.width.raw() as usize;
|
||||
self.pixels.fill_u32(self.pixel(0, bottom - by), by * width, fill.raw());
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
let w = self.width.raw() as u32;
|
||||
let h = self.height.raw() as u32;
|
||||
|
||||
Reference in New Issue
Block a user