mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2024-12-22 21:55:19 +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>,
|
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)]
|
#[cfg(unix)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ScanoutDMABUF {
|
pub struct ScanoutDMABUF {
|
||||||
@ -98,6 +116,12 @@ pub trait ConsoleListenerHandler: 'static + Send + Sync {
|
|||||||
|
|
||||||
async fn update(&mut self, update: Update);
|
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)]
|
#[cfg(unix)]
|
||||||
async fn scanout_dmabuf(&mut self, scanout: ScanoutDMABUF);
|
async fn scanout_dmabuf(&mut self, scanout: ScanoutDMABUF);
|
||||||
|
|
||||||
@ -160,6 +184,57 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||||||
.await;
|
.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))]
|
#[cfg(not(unix))]
|
||||||
#[dbus_interface(name = "ScanoutDMABUF")]
|
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||||
async fn scanout_dmabuf(
|
async fn scanout_dmabuf(
|
||||||
|
@ -19,5 +19,8 @@ rdw = { package = "rdw4", version = "0.1", features = ["bindings"] }
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
uds_windows = "1.0.2"
|
|
||||||
tracing-subscriber = { version = "0.3.11", features = ["env-filter" , "fmt"], default-features = false }
|
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 {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
use gtk::subclass::prelude::*;
|
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)]
|
#[repr(C)]
|
||||||
pub struct RdwDisplayQemuClass {
|
pub struct RdwDisplayQemuClass {
|
||||||
@ -38,10 +44,42 @@ mod imp {
|
|||||||
type Type = Display;
|
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)]
|
#[derive(Debug, Default)]
|
||||||
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(windows)]
|
||||||
|
scanout_map: RefCell<Option<(MemoryMap, u32)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[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);
|
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)]
|
#[cfg(unix)]
|
||||||
ScanoutDMABUF(s) => {
|
ScanoutDMABUF(s) => {
|
||||||
this.obj().set_display_size(Some((s.width as _, s.height as _)));
|
this.obj().set_display_size(Some((s.width as _, s.height as _)));
|
||||||
@ -196,6 +270,7 @@ mod imp {
|
|||||||
log::warn!("Console disconnected");
|
log::warn!("Console disconnected");
|
||||||
}
|
}
|
||||||
CursorDefine(c) => {
|
CursorDefine(c) => {
|
||||||
|
log::debug!("{c:?}");
|
||||||
let cursor = rdw::Display::make_cursor(
|
let cursor = rdw::Display::make_cursor(
|
||||||
&c.data,
|
&c.data,
|
||||||
c.width,
|
c.width,
|
||||||
@ -254,6 +329,10 @@ impl Display {
|
|||||||
enum ConsoleEvent {
|
enum ConsoleEvent {
|
||||||
Scanout(qemu_display::Scanout),
|
Scanout(qemu_display::Scanout),
|
||||||
Update(qemu_display::Update),
|
Update(qemu_display::Update),
|
||||||
|
#[cfg(windows)]
|
||||||
|
ScanoutMap(qemu_display::ScanoutMap),
|
||||||
|
#[cfg(windows)]
|
||||||
|
UpdateMap(qemu_display::UpdateMap),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
ScanoutDMABUF(qemu_display::ScanoutDMABUF),
|
ScanoutDMABUF(qemu_display::ScanoutDMABUF),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -288,6 +367,16 @@ impl ConsoleListenerHandler for ConsoleHandler {
|
|||||||
self.send(ConsoleEvent::Update(update));
|
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)]
|
#[cfg(unix)]
|
||||||
async fn scanout_dmabuf(&mut self, scanout: qemu_display::ScanoutDMABUF) {
|
async fn scanout_dmabuf(&mut self, scanout: qemu_display::ScanoutDMABUF) {
|
||||||
self.send(ConsoleEvent::ScanoutDMABUF(scanout));
|
self.send(ConsoleEvent::ScanoutDMABUF(scanout));
|
||||||
|
Loading…
Reference in New Issue
Block a user