perf(display): present copies window rows as-is (scanout R8G8B8X8 = window byte order, Host hands out row bytes, Framebuffer::write_rgba_row); Window copy_from/copy_to one fenced memcpy; full present ~65ms -> ~3ms
This commit is contained in:
@@ -37,6 +37,11 @@ pub struct VirtioFramebuffer {
|
||||
dirty: Option<(usize, usize, usize, usize)>,
|
||||
}
|
||||
|
||||
/// `c` as the screen stores it: the bytes R, G, B, then one ignored.
|
||||
fn word(c: Color) -> u32 {
|
||||
u32::from_le_bytes(c.to_rgba())
|
||||
}
|
||||
|
||||
impl VirtioFramebuffer {
|
||||
/// Takes over the virtio GPU behind `mmio` and makes a framebuffer its
|
||||
/// scanout. `None` if it is not a GPU or any step fails.
|
||||
@@ -113,6 +118,17 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
self.height
|
||||
}
|
||||
|
||||
fn write_rgba_row(&mut self, x: ScreenCoord, y: ScreenCoord, bytes: &[u8]) {
|
||||
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 n = (bytes.len() / FB_BPP).min(w - x);
|
||||
self.touch(x, y, x + n, y + 1);
|
||||
self.pixels.copy_from(self.pixel(x, y), &bytes[..n * FB_BPP]);
|
||||
}
|
||||
|
||||
fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) {
|
||||
self.write_row(x, y, &[color]);
|
||||
}
|
||||
@@ -129,7 +145,7 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
let mut at = self.pixel(x, y);
|
||||
for chunk in pixels[..n].chunks(RUN) {
|
||||
for (slot, c) in run.iter_mut().zip(chunk) {
|
||||
*slot = c.raw();
|
||||
*slot = word(*c);
|
||||
}
|
||||
self.pixels.write_u32s(at, &run[..chunk.len()]);
|
||||
at = at + chunk.len() * FB_BPP;
|
||||
@@ -144,14 +160,14 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
let bottom = (y + h.raw() as usize).min(fh);
|
||||
self.touch(x, y, x + w, bottom);
|
||||
for row in y..bottom {
|
||||
self.pixels.fill_u32(self.pixel(x, row), w, color.raw());
|
||||
self.pixels.fill_u32(self.pixel(x, row), w, word(color));
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self, color: Color) {
|
||||
let (w, h) = (self.width.raw() as usize, self.height.raw() as usize);
|
||||
self.touch(0, 0, w, h);
|
||||
self.pixels.fill_u32(ByteOffset::ZERO, w * h, color.raw());
|
||||
self.pixels.fill_u32(ByteOffset::ZERO, w * h, word(color));
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self, top: ScreenCoord, height: Dimension, by: Dimension, fill: Color) {
|
||||
@@ -163,7 +179,7 @@ impl Framebuffer for VirtioFramebuffer {
|
||||
self.touch(0, top, self.width.raw() as usize, bottom);
|
||||
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());
|
||||
self.pixels.fill_u32(self.pixel(0, bottom - by), by * width, word(fill));
|
||||
}
|
||||
|
||||
/// Sends the host only what changed since the last flush.
|
||||
|
||||
Reference in New Issue
Block a user