mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2024-12-22 13:45:18 +00:00
win32: add shared scanout map handling
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
f33c9c4659
commit
3712905ec1
@ -32,6 +32,24 @@ pub struct Update {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ScanoutMap {
|
||||
pub handle: u64,
|
||||
pub offset: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub stride: u32,
|
||||
pub format: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct UpdateMap {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub w: i32,
|
||||
pub h: i32,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[derive(Debug)]
|
||||
pub struct ScanoutDMABUF {
|
||||
@ -98,6 +116,12 @@ pub trait ConsoleListenerHandler: 'static + Send + Sync {
|
||||
|
||||
async fn update(&mut self, update: Update);
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn scanout_map(&mut self, scanout: ScanoutMap);
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn update_map(&mut self, update: UpdateMap);
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn scanout_dmabuf(&mut self, scanout: ScanoutDMABUF);
|
||||
|
||||
@ -160,6 +184,57 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn scanout_map(
|
||||
&mut self,
|
||||
handle: u64,
|
||||
offset: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
format: u32,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
let map = ScanoutMap {
|
||||
handle,
|
||||
offset,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
format,
|
||||
};
|
||||
self.handler.scanout_map(map).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
async fn scanout_map(
|
||||
&mut self,
|
||||
_handle: u64,
|
||||
_offset: u32,
|
||||
_width: u32,
|
||||
_height: u32,
|
||||
_stride: u32,
|
||||
_format: u32,
|
||||
) -> zbus::fdo::Result<()> {
|
||||
Err(zbus::fdo::Error::NotSupported(
|
||||
"Shared map is not support on !windows".into(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn update_map(&mut self, x: i32, y: i32, w: i32, h: i32) -> zbus::fdo::Result<()> {
|
||||
let up = UpdateMap { x, y, w, h };
|
||||
self.handler.update_map(up).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
async fn update_map(&mut self, _x: i32, _y: i32, _w: i32, _h: i32) -> zbus::fdo::Result<()> {
|
||||
Err(zbus::fdo::Error::NotSupported(
|
||||
"Shared map is not support on !windows".into(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||
async fn scanout_dmabuf(
|
||||
|
@ -19,5 +19,8 @@ rdw = { package = "rdw4", version = "0.1", features = ["bindings"] }
|
||||
futures-util = "0.3"
|
||||
futures = "0.3"
|
||||
async-trait = "0.1"
|
||||
uds_windows = "1.0.2"
|
||||
tracing-subscriber = { version = "0.3.11", features = ["env-filter" , "fmt"], default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
uds_windows = "1.0.2"
|
||||
windows = { version = "0.43.0", features = ["Win32_System_Memory", "Win32_Foundation"] }
|
||||
|
@ -11,6 +11,12 @@ use std::os::unix::io::IntoRawFd;
|
||||
mod imp {
|
||||
use super::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
#[cfg(windows)]
|
||||
use std::cell::RefCell;
|
||||
#[cfg(windows)]
|
||||
use std::ffi::c_void;
|
||||
#[cfg(windows)]
|
||||
use windows::Win32::Foundation::{CloseHandle, HANDLE};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RdwDisplayQemuClass {
|
||||
@ -38,10 +44,42 @@ mod imp {
|
||||
type Type = Display;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[derive(Debug)]
|
||||
struct MemoryMap {
|
||||
handle: HANDLE,
|
||||
ptr: *const c_void,
|
||||
offset: isize,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl Drop for MemoryMap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
use windows::Win32::System::Memory::UnmapViewOfFile;
|
||||
|
||||
UnmapViewOfFile(self.ptr);
|
||||
CloseHandle(self.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl MemoryMap {
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(self.ptr.cast::<u8>().offset(self.offset), self.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Display {
|
||||
pub(crate) console: OnceCell<Console>,
|
||||
keymap: Cell<Option<&'static [u16]>>,
|
||||
#[cfg(windows)]
|
||||
scanout_map: RefCell<Option<(MemoryMap, u32)>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -174,6 +212,42 @@ mod imp {
|
||||
}
|
||||
this.obj().update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, &u.data);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
ScanoutMap(s) => {
|
||||
use windows::Win32::System::Memory::{FILE_MAP_READ, MapViewOfFile};
|
||||
|
||||
log::debug!("{s:?}");
|
||||
if s.format != 0x20020888 {
|
||||
log::warn!("Format not yet supported: {:X}", s.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 ptr = unsafe { MapViewOfFile(handle, FILE_MAP_READ, 0, 0, s.offset as usize + size) };
|
||||
if ptr.is_null() {
|
||||
log::warn!("Failed to map scanout!");
|
||||
continue;
|
||||
}
|
||||
|
||||
let map = MemoryMap { ptr, handle, offset, size };
|
||||
this.obj().set_display_size(Some((s.width as _, s.height as _)));
|
||||
this.obj().update_area(0, 0, s.width as _, s.height as _, s.stride as _, map.as_bytes());
|
||||
this.scanout_map.replace(Some((map, s.stride)));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
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_bytes();
|
||||
this.obj().update_area(u.x as _, u.y as _, u.w as _, u.h as _, stride as _, &bytes[u.y as usize * stride as usize + u.x as usize * 4..]);
|
||||
}
|
||||
#[cfg(unix)]
|
||||
ScanoutDMABUF(s) => {
|
||||
this.obj().set_display_size(Some((s.width as _, s.height as _)));
|
||||
@ -196,6 +270,7 @@ mod imp {
|
||||
log::warn!("Console disconnected");
|
||||
}
|
||||
CursorDefine(c) => {
|
||||
log::debug!("{c:?}");
|
||||
let cursor = rdw::Display::make_cursor(
|
||||
&c.data,
|
||||
c.width,
|
||||
@ -254,6 +329,10 @@ impl Display {
|
||||
enum ConsoleEvent {
|
||||
Scanout(qemu_display::Scanout),
|
||||
Update(qemu_display::Update),
|
||||
#[cfg(windows)]
|
||||
ScanoutMap(qemu_display::ScanoutMap),
|
||||
#[cfg(windows)]
|
||||
UpdateMap(qemu_display::UpdateMap),
|
||||
#[cfg(unix)]
|
||||
ScanoutDMABUF(qemu_display::ScanoutDMABUF),
|
||||
#[cfg(unix)]
|
||||
@ -288,6 +367,16 @@ impl ConsoleListenerHandler for ConsoleHandler {
|
||||
self.send(ConsoleEvent::Update(update));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn scanout_map(&mut self, scanout: qemu_display::ScanoutMap) {
|
||||
self.send(ConsoleEvent::ScanoutMap(scanout));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn update_map(&mut self, update: qemu_display::UpdateMap) {
|
||||
self.send(ConsoleEvent::UpdateMap(update));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn scanout_dmabuf(&mut self, scanout: qemu_display::ScanoutDMABUF) {
|
||||
self.send(ConsoleEvent::ScanoutDMABUF(scanout));
|
||||
|
Loading…
Reference in New Issue
Block a user