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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap2"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@ -3359,6 +3368,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"libc",
|
"libc",
|
||||||
|
"memmap2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pixman-sys",
|
"pixman-sys",
|
||||||
"qapi",
|
"qapi",
|
||||||
|
@ -29,6 +29,7 @@ async-trait = "0.1"
|
|||||||
async-lock = "3.4"
|
async-lock = "3.4"
|
||||||
qapi = { version = "0.14", features = ["qmp"], optional = true }
|
qapi = { version = "0.14", features = ["qmp"], optional = true }
|
||||||
base64 = { version = "0.22", optional = true }
|
base64 = { version = "0.22", optional = true }
|
||||||
|
memmap2 = "0.9.5"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
uds_windows = "1.1"
|
uds_windows = "1.1"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
pub use zbus;
|
pub use zbus;
|
||||||
|
pub use memmap2;
|
||||||
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
|
use std::os::fd::RawFd;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
#[cfg(windows)]
|
#[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 _))
|
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 glib::{clone, subclass::prelude::*, MainContext};
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use qemu_display::{Console, ConsoleListenerHandler};
|
|
||||||
#[cfg(windows)]
|
#[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 rdw::{gtk, DisplayExt};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -13,10 +15,12 @@ use std::os::unix::io::IntoRawFd;
|
|||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
#[cfg(windows)]
|
use qemu_display::{memmap2::Mmap, util::mmap};
|
||||||
|
#[cfg(any(windows, unix))]
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
use std::os::fd::AsRawFd;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use windows::Win32::Foundation::{CloseHandle, HANDLE};
|
use windows::Win32::Foundation::{CloseHandle, HANDLE};
|
||||||
|
|
||||||
@ -80,6 +84,8 @@ mod imp {
|
|||||||
pub struct Display {
|
pub struct Display {
|
||||||
pub(crate) console: OnceCell<Console>,
|
pub(crate) console: OnceCell<Console>,
|
||||||
keymap: Cell<Option<&'static [u16]>>,
|
keymap: Cell<Option<&'static [u16]>>,
|
||||||
|
#[cfg(unix)]
|
||||||
|
scanout_map: RefCell<Option<(Mmap, u32)>>,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
scanout_map: RefCell<Option<(MemoryMap, u32)>>,
|
scanout_map: RefCell<Option<(MemoryMap, u32)>>,
|
||||||
}
|
}
|
||||||
@ -275,11 +281,10 @@ mod imp {
|
|||||||
let (sender, mut receiver) = futures::channel::mpsc::unbounded();
|
let (sender, mut receiver) = futures::channel::mpsc::unbounded();
|
||||||
let handler = ConsoleHandler { sender };
|
let handler = ConsoleHandler { sender };
|
||||||
console.register_listener(handler.clone()).await.unwrap();
|
console.register_listener(handler.clone()).await.unwrap();
|
||||||
|
#[cfg(any(windows, unix))]
|
||||||
|
console.set_map_listener(handler.clone()).await.unwrap();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
console.set_d3d11_listener(handler.clone()).await.unwrap();
|
||||||
console.set_map_listener(handler.clone()).await.unwrap();
|
|
||||||
console.set_d3d11_listener(handler.clone()).await.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
MainContext::default().spawn_local(clone!(
|
MainContext::default().spawn_local(clone!(
|
||||||
#[weak]
|
#[weak]
|
||||||
@ -318,28 +323,79 @@ mod imp {
|
|||||||
Some(&u.data),
|
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)]
|
#[cfg(windows)]
|
||||||
ScanoutMap(s) => {
|
ScanoutMap { scanout, wait_tx } => {
|
||||||
use windows::Win32::System::Memory::{
|
use windows::Win32::System::Memory::{
|
||||||
MapViewOfFile, FILE_MAP_READ,
|
MapViewOfFile, FILE_MAP_READ,
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug!("{s:?}");
|
log::debug!("{s:?}");
|
||||||
if s.format != 0x20020888 {
|
if scanout.format != 0x20020888 {
|
||||||
log::warn!("Format not yet supported: {:X}", s.format);
|
log::warn!(
|
||||||
|
"Format not yet supported: {:X}",
|
||||||
|
scanout.format
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = HANDLE(s.handle as _);
|
let handle = HANDLE(scanout.handle as _);
|
||||||
let size = s.height as usize * s.stride as usize;
|
let size =
|
||||||
let offset = s.offset as isize;
|
scanout.height as usize * scanout.stride as usize;
|
||||||
|
let offset = scanout.offset as isize;
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
MapViewOfFile(
|
MapViewOfFile(
|
||||||
handle,
|
handle,
|
||||||
FILE_MAP_READ,
|
FILE_MAP_READ,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
s.offset as usize + size,
|
scanout.offset as usize + size,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
@ -353,17 +409,20 @@ mod imp {
|
|||||||
offset,
|
offset,
|
||||||
size,
|
size,
|
||||||
};
|
};
|
||||||
this.obj()
|
this.obj().set_display_size(Some((
|
||||||
.set_display_size(Some((s.width as _, s.height as _)));
|
scanout.width as _,
|
||||||
|
scanout.height as _,
|
||||||
|
)));
|
||||||
this.obj().update_area(
|
this.obj().update_area(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
s.width as _,
|
scanout.width as _,
|
||||||
s.height as _,
|
scanout.height as _,
|
||||||
s.stride as _,
|
scanout.stride as _,
|
||||||
Some(map.as_bytes()),
|
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)]
|
#[cfg(windows)]
|
||||||
UpdateMap(u) => {
|
UpdateMap(u) => {
|
||||||
@ -504,9 +563,12 @@ impl Display {
|
|||||||
enum ConsoleEvent {
|
enum ConsoleEvent {
|
||||||
Scanout(qemu_display::Scanout),
|
Scanout(qemu_display::Scanout),
|
||||||
Update(qemu_display::Update),
|
Update(qemu_display::Update),
|
||||||
#[cfg(windows)]
|
#[cfg(any(windows, unix))]
|
||||||
ScanoutMap(qemu_display::ScanoutMap),
|
ScanoutMap {
|
||||||
#[cfg(windows)]
|
scanout: qemu_display::ScanoutMap,
|
||||||
|
wait_tx: futures::channel::oneshot::Sender<()>,
|
||||||
|
},
|
||||||
|
#[cfg(any(windows, unix))]
|
||||||
UpdateMap(qemu_display::UpdateMap),
|
UpdateMap(qemu_display::UpdateMap),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
ScanoutD3dTexture2d(qemu_display::ScanoutD3dTexture2d),
|
ScanoutD3dTexture2d(qemu_display::ScanoutD3dTexture2d),
|
||||||
@ -541,15 +603,17 @@ impl ConsoleHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(any(windows, unix))]
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl ConsoleListenerMapHandler for ConsoleHandler {
|
impl ConsoleListenerMapHandler for ConsoleHandler {
|
||||||
#[cfg(windows)]
|
|
||||||
async fn scanout_map(&mut self, scanout: qemu_display::ScanoutMap) {
|
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) {
|
async fn update_map(&mut self, update: qemu_display::UpdateMap) {
|
||||||
self.send(ConsoleEvent::UpdateMap(update));
|
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.Map".to_string(),
|
||||||
"org.qemu.Display1.Listener.Win32.D3d11".to_string(),
|
"org.qemu.Display1.Listener.Win32.D3d11".to_string(),
|
||||||
]
|
]
|
||||||
|
} else if cfg!(unix) {
|
||||||
|
vec!["org.qemu.Display1.Listener.Unix.Map".to_string()]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user