blob: 50380e983a31ef235aefb70016fae3d3c09e92cb [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context as _, Error};
use fuchsia_async::{self as fasync, DurationExt, Timer};
use fuchsia_framebuffer::{FrameBuffer, FrameUsage, ImageId, PixelFormat, VSyncMessage};
use fuchsia_zircon::DurationNum;
use futures::{channel::mpsc::unbounded, StreamExt};
use std::{cell::RefCell, rc::Rc};
fn to_565(pixel: &[u8; 4]) -> [u8; 2] {
let red = pixel[0] >> 3;
let green = pixel[1] >> 2;
let blue = pixel[2] >> 3;
let b1 = (red << 3) | ((green & 0b11_1000) >> 3);
let b2 = ((green & 0b111) << 5) | blue;
[b2, b1]
}
#[derive(Debug, PartialEq)]
enum TestResult {
TimeoutFired,
TestPassed,
}
fn test_main() -> Result<(), Error> {
println!("fuchsia_framebuffer_integration_test");
let mut executor = fasync::Executor::new().context("Failed to create executor")?;
executor.run_singlethreaded(async {
let (test_sender, mut test_receiver) = unbounded::<TestResult>();
let timeout_sender = test_sender.clone();
let (sender, mut receiver) = unbounded::<VSyncMessage>();
let mut fb = FrameBuffer::new(FrameUsage::Cpu, None, Some(sender))
.await
.context("Failed to create framebuffer, perhaps a root presenter is already running")?;
let config = fb.get_config();
fb.allocate_frames(2, config.format).await?;
let image_ids: Vec<ImageId> = fb.get_image_ids().into_iter().collect();
let (image_sender, mut image_receiver) = unbounded::<u64>();
let image_id_1 = image_ids[0];
let frame = fb.get_frame_mut(image_id_1);
let grey = [0x80, 0x80, 0x80, 0xFF];
if config.format != PixelFormat::Rgb565 {
frame.fill_rectangle(0, 0, config.width, config.height, &grey);
} else {
frame.fill_rectangle(0, 0, config.width, config.height, &to_565(&grey));
}
fb.flush_frame(image_id_1)?;
fb.present_frame(image_id_1, Some(image_sender), true)?;
let image_id_2 = image_ids[1];
let fb_ptr = Rc::new(RefCell::new(fb));
// Listen for vsync messages to schedule an update of the displayed image
fasync::Task::local(async move {
receiver.next().await;
let mut fb = fb_ptr.borrow_mut();
let frame2 = fb.get_frame_mut(image_id_2);
let white = [0x0ff, 0xff, 0xff, 0xFF];
if config.format != PixelFormat::Rgb565 {
frame2.fill_rectangle(0, 0, config.width, config.height, &white);
} else {
frame2.fill_rectangle(0, 0, config.width, config.height, &to_565(&white));
}
fb.flush_frame(image_id_2).expect("flush_frame");
fb.present_frame(image_id_2, None, true).expect("frame2 present to succeed");
image_receiver.next().await;
test_sender.unbounded_send(TestResult::TestPassed).unwrap();
})
.detach();
let timeout = Timer::new(5_i64.second().after_now());
fasync::Task::local(async move {
timeout.await;
timeout_sender
.unbounded_send(TestResult::TimeoutFired)
.expect("test_sender.send expected to work");
})
.detach();
let r = test_receiver.next().await;
assert_eq!(r.unwrap(), TestResult::TestPassed);
Ok::<(), Error>(())
})?;
Ok(())
}
fn main() -> Result<(), Error> {
test_main()
}
#[cfg(test)]
mod test {
use crate::test_main;
#[test]
fn fb_integration_test() -> std::result::Result<(), anyhow::Error> {
test_main()
}
}