mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2024-12-22 05:35:20 +00:00
display/rdw: implement Unix.Map
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
5e9292057b
commit
6801ea795c
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -2626,6 +2626,15 @@ version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
@ -3359,6 +3368,7 @@ dependencies = [
|
||||
"futures",
|
||||
"futures-util",
|
||||
"libc",
|
||||
"memmap2",
|
||||
"once_cell",
|
||||
"pixman-sys",
|
||||
"qapi",
|
||||
|
@ -29,6 +29,7 @@ async-trait = "0.1"
|
||||
async-lock = "3.4"
|
||||
qapi = { version = "0.14", features = ["qmp"], optional = true }
|
||||
base64 = { version = "0.22", optional = true }
|
||||
memmap2 = "0.9.5"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
uds_windows = "1.1"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
pub use zbus;
|
||||
pub use memmap2;
|
||||
|
||||
pub mod util;
|
||||
#[cfg(windows)]
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::Result;
|
||||
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::net::UnixStream;
|
||||
#[cfg(windows)]
|
||||
@ -30,3 +32,8 @@ pub fn prepare_uds_pass(#[cfg(windows)] peer_pid: u32, us: &UnixStream) -> Resul
|
||||
p.duplicate_socket(SOCKET(us.as_raw_socket() as _))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub unsafe fn mmap(fd: RawFd, len: usize, offset: u64) -> std::io::Result<memmap2::Mmap> {
|
||||
memmap2::MmapOptions::new().len(len).offset(offset).map(fd)
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ use futures_util::StreamExt;
|
||||
use glib::{clone, subclass::prelude::*, MainContext};
|
||||
use gtk::glib;
|
||||
use once_cell::sync::OnceCell;
|
||||
use qemu_display::{Console, ConsoleListenerHandler};
|
||||
#[cfg(windows)]
|
||||
use qemu_display::{ConsoleListenerD3d11Handler, ConsoleListenerMapHandler};
|
||||
use qemu_display::ConsoleListenerD3d11Handler;
|
||||
#[cfg(any(windows, unix))]
|
||||
use qemu_display::ConsoleListenerMapHandler;
|
||||
use qemu_display::{Console, ConsoleListenerHandler};
|
||||
use rdw::{gtk, DisplayExt};
|
||||
use std::cell::Cell;
|
||||
#[cfg(unix)]
|
||||
@ -13,10 +15,12 @@ use std::os::unix::io::IntoRawFd;
|
||||
mod imp {
|
||||
use super::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
#[cfg(windows)]
|
||||
use qemu_display::{memmap2::Mmap, util::mmap};
|
||||
#[cfg(any(windows, unix))]
|
||||
use std::cell::RefCell;
|
||||
#[cfg(windows)]
|
||||
use std::ffi::c_void;
|
||||
use std::os::fd::AsRawFd;
|
||||
#[cfg(windows)]
|
||||
use windows::Win32::Foundation::{CloseHandle, HANDLE};
|
||||
|
||||
@ -80,6 +84,8 @@ mod imp {
|
||||
pub struct Display {
|
||||
pub(crate) console: OnceCell<Console>,
|
||||
keymap: Cell<Option<&'static [u16]>>,
|
||||
#[cfg(unix)]
|
||||
scanout_map: RefCell<Option<(Mmap, u32)>>,
|
||||
#[cfg(windows)]
|
||||
scanout_map: RefCell<Option<(MemoryMap, u32)>>,
|
||||
}
|
||||
@ -275,11 +281,10 @@ mod imp {
|
||||
let (sender, mut receiver) = futures::channel::mpsc::unbounded();
|
||||
let handler = ConsoleHandler { sender };
|
||||
console.register_listener(handler.clone()).await.unwrap();
|
||||
#[cfg(any(windows, unix))]
|
||||
console.set_map_listener(handler.clone()).await.unwrap();
|
||||
#[cfg(windows)]
|
||||
{
|
||||
console.set_map_listener(handler.clone()).await.unwrap();
|
||||
console.set_d3d11_listener(handler.clone()).await.unwrap();
|
||||
}
|
||||
console.set_d3d11_listener(handler.clone()).await.unwrap();
|
||||
|
||||
MainContext::default().spawn_local(clone!(
|
||||
#[weak]
|
||||
@ -318,28 +323,79 @@ mod imp {
|
||||
Some(&u.data),
|
||||
);
|
||||
}
|
||||
#[cfg(unix)]
|
||||
ScanoutMap { scanout, wait_tx } => {
|
||||
log::debug!("{scanout:?}");
|
||||
if scanout.format != 0x20020888 {
|
||||
log::warn!(
|
||||
"Format not yet supported: {:X}",
|
||||
scanout.format
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let map = unsafe {
|
||||
mmap(
|
||||
scanout.fd.as_raw_fd(),
|
||||
scanout.height as usize * scanout.stride as usize,
|
||||
scanout.offset.into(),
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
this.obj().set_display_size(Some((
|
||||
scanout.width as _,
|
||||
scanout.height as _,
|
||||
)));
|
||||
this.scanout_map.replace(Some((map, scanout.stride)));
|
||||
let _ = wait_tx.send(());
|
||||
}
|
||||
#[cfg(unix)]
|
||||
UpdateMap(u) => {
|
||||
log::debug!("{u:?}");
|
||||
let scanout_map = this.scanout_map.borrow();
|
||||
let Some((map, stride)) = scanout_map.as_ref() else {
|
||||
log::warn!("No mapped scanout!");
|
||||
continue;
|
||||
};
|
||||
let stride = *stride;
|
||||
let bytes = map.as_ref();
|
||||
this.obj().update_area(
|
||||
u.x as _,
|
||||
u.y as _,
|
||||
u.w as _,
|
||||
u.h as _,
|
||||
stride as _,
|
||||
Some(
|
||||
&bytes[u.y as usize * stride as usize
|
||||
+ u.x as usize * 4..],
|
||||
),
|
||||
);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
ScanoutMap(s) => {
|
||||
ScanoutMap { scanout, wait_tx } => {
|
||||
use windows::Win32::System::Memory::{
|
||||
MapViewOfFile, FILE_MAP_READ,
|
||||
};
|
||||
|
||||
log::debug!("{s:?}");
|
||||
if s.format != 0x20020888 {
|
||||
log::warn!("Format not yet supported: {:X}", s.format);
|
||||
if scanout.format != 0x20020888 {
|
||||
log::warn!(
|
||||
"Format not yet supported: {:X}",
|
||||
scanout.format
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let handle = HANDLE(s.handle as _);
|
||||
let size = s.height as usize * s.stride as usize;
|
||||
let offset = s.offset as isize;
|
||||
let handle = HANDLE(scanout.handle as _);
|
||||
let size =
|
||||
scanout.height as usize * scanout.stride as usize;
|
||||
let offset = scanout.offset as isize;
|
||||
let ptr = unsafe {
|
||||
MapViewOfFile(
|
||||
handle,
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
s.offset as usize + size,
|
||||
scanout.offset as usize + size,
|
||||
)
|
||||
};
|
||||
if ptr.is_null() {
|
||||
@ -353,17 +409,20 @@ mod imp {
|
||||
offset,
|
||||
size,
|
||||
};
|
||||
this.obj()
|
||||
.set_display_size(Some((s.width as _, s.height as _)));
|
||||
this.obj().set_display_size(Some((
|
||||
scanout.width as _,
|
||||
scanout.height as _,
|
||||
)));
|
||||
this.obj().update_area(
|
||||
0,
|
||||
0,
|
||||
s.width as _,
|
||||
s.height as _,
|
||||
s.stride as _,
|
||||
scanout.width as _,
|
||||
scanout.height as _,
|
||||
scanout.stride as _,
|
||||
Some(map.as_bytes()),
|
||||
);
|
||||
this.scanout_map.replace(Some((map, s.stride)));
|
||||
this.scanout_map.replace(Some((map, scanout.stride)));
|
||||
let _ = wait_tx.send(());
|
||||
}
|
||||
#[cfg(windows)]
|
||||
UpdateMap(u) => {
|
||||
@ -504,9 +563,12 @@ impl Display {
|
||||
enum ConsoleEvent {
|
||||
Scanout(qemu_display::Scanout),
|
||||
Update(qemu_display::Update),
|
||||
#[cfg(windows)]
|
||||
ScanoutMap(qemu_display::ScanoutMap),
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(windows, unix))]
|
||||
ScanoutMap {
|
||||
scanout: qemu_display::ScanoutMap,
|
||||
wait_tx: futures::channel::oneshot::Sender<()>,
|
||||
},
|
||||
#[cfg(any(windows, unix))]
|
||||
UpdateMap(qemu_display::UpdateMap),
|
||||
#[cfg(windows)]
|
||||
ScanoutD3dTexture2d(qemu_display::ScanoutD3dTexture2d),
|
||||
@ -541,15 +603,17 @@ impl ConsoleHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(any(windows, unix))]
|
||||
#[async_trait::async_trait]
|
||||
impl ConsoleListenerMapHandler for ConsoleHandler {
|
||||
#[cfg(windows)]
|
||||
async fn scanout_map(&mut self, scanout: qemu_display::ScanoutMap) {
|
||||
self.send(ConsoleEvent::ScanoutMap(scanout));
|
||||
let (wait_tx, wait_rx) = futures::channel::oneshot::channel();
|
||||
self.send(ConsoleEvent::ScanoutMap { scanout, wait_tx });
|
||||
if let Err(e) = wait_rx.await {
|
||||
log::warn!("wait update d3d texture2d failed: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn update_map(&mut self, update: qemu_display::UpdateMap) {
|
||||
self.send(ConsoleEvent::UpdateMap(update));
|
||||
}
|
||||
@ -620,6 +684,8 @@ impl ConsoleListenerHandler for ConsoleHandler {
|
||||
"org.qemu.Display1.Listener.Win32.Map".to_string(),
|
||||
"org.qemu.Display1.Listener.Win32.D3d11".to_string(),
|
||||
]
|
||||
} else if cfg!(unix) {
|
||||
vec!["org.qemu.Display1.Listener.Unix.Map".to_string()]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user