vnc: now display the framebuffer/scanout

This commit is contained in:
Marc-André Lureau 2021-03-08 00:52:27 +04:00
parent 0f75905cc8
commit 124d893395
3 changed files with 61 additions and 19 deletions

View File

@ -10,4 +10,4 @@ members = [
[patch.crates-io]
zbus = { path = '/home/elmarco/src/zbus/zbus' }
zvariant = { path = '/home/elmarco/src/zbus/zvariant' }
vnc = { git = 'https://github.com/elmarco/rust-vnc', branch = 'server' }
vnc = { path = '/home/elmarco/src/rust-vnc' }

View File

@ -12,3 +12,4 @@ vnc = "0.4.0"
clap = "3.0.0-beta.2"
zbus = { version = "2.0.0-beta" }
libc = "0.2.86"
image = "0.23.14"

View File

@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex};
use std::{io, thread, time};
use clap::Clap;
use image::GenericImage;
use qemu_display_listener::{Console, ConsoleEvent};
use vnc::{
server::Event as VncEvent, server::FramebufferUpdate, Error as VncError, PixelFormat, Rect,
@ -33,28 +34,39 @@ struct Cli {
address: SocketAddrArgs,
}
const PIXMAN_X8R8G8B8: u32 = 0x20020888;
type BgraImage = image::ImageBuffer<image::Bgra<u8>, Vec<u8>>;
#[derive(Debug)]
struct ServerInner {
width: u16,
height: u16,
image: BgraImage,
}
#[derive(Clone, Debug)]
struct Server {
inner: Arc<Mutex<ServerInner>>,
}
impl Server {
fn new(width: u16, height: u16) -> Self {
let image = BgraImage::new(width as _, height as _);
Self {
inner: Arc::new(Mutex::new(ServerInner { width, height })),
inner: Arc::new(Mutex::new(ServerInner { image })),
}
}
fn width_height(&self) -> (u16, u16) {
let inner = self.inner.lock().unwrap();
(inner.image.width() as u16, inner.image.height() as u16)
}
fn handle_client(&self, stream: TcpStream) -> Result<(), Box<dyn Error>> {
stream.set_read_timeout(Some(time::Duration::from_millis(100)))?;
let (width, height) = self.width_height();
let (mut server, _share) = VncServer::from_tcp_stream(
stream,
self.inner.lock().unwrap().width,
self.inner.lock().unwrap().height,
width,
height,
PixelFormat::rgb8888(),
"qemu-vnc experiment".into(),
)?;
@ -80,13 +92,14 @@ impl Server {
}
}
last_update = Some(time::Instant::now());
let inner = self.inner.lock().unwrap();
let mut fbu = FramebufferUpdate::new(&PixelFormat::rgb8888());
let pixel_data = vec![128; 8 * 8 * 4];
let pixel_data = inner.image.as_raw();
let rect = Rect {
left: 0,
top: 0,
width: 8,
height: 8,
width: inner.image.width() as u16,
height: inner.image.height() as u16,
};
fbu.add_raw_pixels(rect, &pixel_data);
server.send(&fbu)?;
@ -105,20 +118,48 @@ fn main() -> Result<(), Box<dyn Error>> {
let listener = TcpListener::bind::<std::net::SocketAddr>(args.address.into()).unwrap();
let conn = Connection::new_session().expect("Failed to connect to DBus");
let console = Console::new(&conn, 0).expect("Failed to get the console");
let (rx, ack) = console.listen()?;
let (rx, _ack) = console.listen()?;
let server = Server::new(console.width()? as u16, console.height()? as u16);
let _thread = thread::spawn(move || match rx.recv().unwrap() {
ConsoleEvent::ScanoutDMABUF(s) => {
dbg!(&s);
unsafe {
libc::close(s.fd);
let srv = server.clone();
let _thread = thread::spawn(move || loop {
match rx.recv().unwrap() {
ConsoleEvent::ScanoutDMABUF(_) => {
unimplemented!();
}
ConsoleEvent::Scanout(s) => {
if s.format != PIXMAN_X8R8G8B8 {
todo!()
}
let layout = image::flat::SampleLayout {
channels: 4,
channel_stride: 1,
width: s.width,
width_stride: 4,
height: s.height,
height_stride: s.stride as _,
};
let samples = image::flat::FlatSamples {
samples: s.data,
layout,
color_hint: None,
};
let img = match samples.try_into_buffer::<image::Bgra<u8>>() {
Ok(buf) => buf,
Err((_, samples)) => {
let view = samples.as_view::<image::Bgra<u8>>().unwrap();
let mut img = BgraImage::new(s.width, s.height);
img.copy_from(&view, 0, 0).unwrap();
img
}
};
let mut inner = srv.inner.lock().unwrap();
inner.image = img;
}
e => {
dbg!(e);
}
let _ = ack.send(());
}
e => {
dbg!(e);
}
});
for stream in listener.incoming() {