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:
@@ -15,7 +15,8 @@ const H: usize = 16 + 8;
|
||||
/// Buffers in memory; a capability is its slot number plus 40.
|
||||
#[derive(Default)]
|
||||
struct FakeHost {
|
||||
buffers: Vec<Option<Vec<Color>>>,
|
||||
/// Each slot's pixels, the bytes R, G, B, A.
|
||||
buffers: Vec<Option<Vec<u8>>>,
|
||||
minted: Vec<usize>,
|
||||
revoked: Vec<CapSlot>,
|
||||
reclaimed: Vec<usize>,
|
||||
@@ -28,17 +29,16 @@ impl Host for FakeHost {
|
||||
if self.buffers.len() <= index {
|
||||
self.buffers.resize(index + 1, None);
|
||||
}
|
||||
self.buffers[index].get_or_insert_with(|| vec![Color::from_raw(0); pixels]);
|
||||
self.buffers[index].get_or_insert_with(|| vec![0; pixels * 4]);
|
||||
CapSlot::new(40 + index as u8)
|
||||
}
|
||||
fn blank(&mut self, index: usize) {
|
||||
if let Some(b) = self.buffers[index].as_mut() {
|
||||
b.fill(Color::from_raw(0));
|
||||
b.fill(0);
|
||||
}
|
||||
}
|
||||
fn read(&self, index: usize, from: usize, out: &mut [Color]) {
|
||||
let b = self.buffers[index].as_ref().unwrap();
|
||||
out.copy_from_slice(&b[from..from + out.len()]);
|
||||
fn pixels(&self, index: usize, from: usize, count: usize) -> &[u8] {
|
||||
&self.buffers[index].as_ref().unwrap()[from * 4..(from + count) * 4]
|
||||
}
|
||||
fn reclaim(&mut self, index: usize) {
|
||||
self.reclaimed.push(index);
|
||||
@@ -58,6 +58,13 @@ impl Host for FakeHost {
|
||||
}
|
||||
}
|
||||
|
||||
/// A window buffer all one colour, as an app would draw it.
|
||||
fn fill(buf: &mut [u8], c: Color) {
|
||||
for px in buf.chunks_exact_mut(4) {
|
||||
px.copy_from_slice(&c.to_rgba());
|
||||
}
|
||||
}
|
||||
|
||||
type Srv = DisplayServer<GridFramebuffer<W, H>, FakeHost>;
|
||||
|
||||
fn server() -> Srv {
|
||||
@@ -76,7 +83,7 @@ fn open(s: &mut Srv, opener: usize, name: &[u8]) -> usize {
|
||||
/// Paints window `slot`'s buffer one colour and presents all of it.
|
||||
fn paint(s: &mut Srv, badge: usize, slot: usize, color: Color) -> [usize; 4] {
|
||||
// The app writes its buffer directly; here, through the fake.
|
||||
s.host_mut_for_test().buffers[slot].as_mut().unwrap().fill(color);
|
||||
fill(s.host_mut_for_test().buffers[slot].as_mut().unwrap(), color);
|
||||
let rect = w::pack_rect(
|
||||
types::display::ScreenCoord::new(0),
|
||||
types::display::ScreenCoord::new(0),
|
||||
@@ -156,9 +163,9 @@ fn closing_takes_the_window_and_its_buffer_back() {
|
||||
assert_eq!(shown(&s), Some(BLUE), "the terminal is in front again");
|
||||
assert_eq!(s.handle_call(snake, [w::POLL, 0, 0, 0], None).0[0], MALFORMED, "closed");
|
||||
// Its buffer is reused, blank, for the next window.
|
||||
s.host_mut_for_test().buffers[1].as_mut().unwrap().fill(RED);
|
||||
fill(s.host_mut_for_test().buffers[1].as_mut().unwrap(), RED);
|
||||
open(&mut s, 2, b"Snake");
|
||||
assert!(s.host().buffers[1].as_ref().unwrap().iter().all(|c| *c == Color::from_raw(0)));
|
||||
assert!(s.host().buffers[1].as_ref().unwrap().iter().all(|b| *b == 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -176,7 +183,7 @@ fn a_launcher_gone_takes_its_windows_with_it() {
|
||||
fn a_present_outside_the_window_is_clipped() {
|
||||
let mut s = server();
|
||||
let t = open(&mut s, 1, b"Terminal");
|
||||
s.host_mut_for_test().buffers[0].as_mut().unwrap().fill(RED);
|
||||
fill(s.host_mut_for_test().buffers[0].as_mut().unwrap(), RED);
|
||||
let rect = w::pack_rect(
|
||||
types::display::ScreenCoord::new(30),
|
||||
types::display::ScreenCoord::new(5),
|
||||
|
||||
Reference in New Issue
Block a user