Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions examples/gui_vm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ use gtk_display::{
use krun_sys::{
KRUN_LOG_LEVEL_TRACE, KRUN_LOG_LEVEL_WARN, KRUN_LOG_STYLE_ALWAYS, KRUN_LOG_TARGET_DEFAULT,
VIRGLRENDERER_RENDER_SERVER, VIRGLRENDERER_THREAD_SYNC, VIRGLRENDERER_USE_ASYNC_FENCE_CB,
VIRGLRENDERER_USE_EGL, VIRGLRENDERER_VENUS, krun_add_display, krun_add_input_device,
krun_add_input_device_fd, krun_create_ctx, krun_display_set_dpi,
VIRGLRENDERER_USE_EGL, VIRGLRENDERER_USE_EXTERNAL_BLOB, VIRGLRENDERER_VENUS, krun_add_display,
krun_add_input_device, krun_add_input_device_fd, krun_create_ctx, krun_display_set_dpi,
krun_display_set_physical_size, krun_display_set_refresh_rate, krun_init_log,
krun_set_display_backend, krun_set_exec, krun_set_gpu_options2, krun_set_root,
krun_set_vm_config, krun_start_enter,
};
use log::LevelFilter;
use regex::{Captures, Regex};
use std::ffi::{CString, c_void};
use std::fmt::Display;
Expand Down Expand Up @@ -156,8 +155,9 @@ fn krun_thread(
| VIRGLRENDERER_VENUS
| VIRGLRENDERER_RENDER_SERVER
| VIRGLRENDERER_THREAD_SYNC
| VIRGLRENDERER_USE_ASYNC_FENCE_CB,
4096
| VIRGLRENDERER_USE_ASYNC_FENCE_CB
| VIRGLRENDERER_USE_EXTERNAL_BLOB,
1 << 32
))?;

krun_call!(krun_set_root(ctx, args.root_dir.as_ptr()))?;
Expand Down Expand Up @@ -224,9 +224,7 @@ fn krun_thread(
}

fn main() -> anyhow::Result<()> {
env_logger::builder()
.filter_level(LevelFilter::Debug)
.init();
env_logger::builder().parse_env("GUI_VM_LOG").init();
let args = Args::parse();

let mut per_display_inputs = vec![vec![]; args.display.len()];
Expand Down
111 changes: 106 additions & 5 deletions examples/krun_gtk_display/src/display_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use krun_display::{
DisplayBackendBasicFramebuffer, DisplayBackendError, DisplayBackendNew, MAX_DISPLAYS, Rect,
ResourceFormat,
};
#[cfg(target_os = "linux")]
use krun_display::{DisplayBackendDmabuf, DmabufExport};
use log::error;
use std::mem;
use utils::pollable_channel::PollableChannelSender;
Expand All @@ -21,6 +23,15 @@ const _: () = {

#[derive(Debug, Clone)]
pub enum DisplayEvent {
#[cfg(target_os = "linux")]
ImportDmabuf {
dmabuf_id: u32,
dmabuf_export: DmabufExport,
},
#[cfg(target_os = "linux")]
UnrefDmabuf {
dmabuf_id: u32,
},
ConfigureScanout {
scanout_id: u32,
display_width: u32,
Expand All @@ -29,6 +40,14 @@ pub enum DisplayEvent {
height: u32,
format: MemoryFormat,
},
#[cfg(target_os = "linux")]
ConfigureScanoutDmabuf {
scanout_id: u32,
display_width: u32,
display_height: u32,
dmabuf_id: u32,
src_rect: Option<Rect>,
},
DisableScanout {
scanout_id: u32,
},
Expand All @@ -37,24 +56,32 @@ pub enum DisplayEvent {
buffer: Bytes,
rect: Option<Rect>,
},
#[cfg(target_os = "linux")]
UpdateScanoutDmabuf {
scanout_id: u32,
rect: Option<Rect>,
},
}

// Implements libkrun traits (callbacks) to provide a display implementation, by forwarding the
// events to the `DisplayWorker`
pub struct GtkDisplayBackend {
channel: PollableChannelSender<DisplayEvent>,
scanouts: [Option<Scanout>; MAX_DISPLAYS],
#[cfg(target_os = "linux")]
next_dmabuf_id: u32,
}

impl DisplayBackendNew<PollableChannelSender<DisplayEvent>> for GtkDisplayBackend {
fn new(channel: Option<&PollableChannelSender<DisplayEvent>>) -> Self {
let channel = channel
.expect("The channel should have been set by GtkDisplayBackend::into_display_backend")
.clone();
fn new(userdata: Option<&PollableChannelSender<DisplayEvent>>) -> Self {
let channel = userdata
.expect("The userdata should have been set by GtkDisplayBackend::into_display_backend");

Self {
channel,
channel: channel.clone(),
scanouts: Default::default(),
#[cfg(target_os = "linux")]
next_dmabuf_id: 1,
}
}
}
Expand Down Expand Up @@ -89,6 +116,8 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
buffer_rx,
buffer_tx,
current_buffer: Vec::new(),
#[cfg(target_os = "linux")]
has_dmabuf: false,
});
}

Expand Down Expand Up @@ -157,6 +186,76 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
}
}

#[cfg(target_os = "linux")]
impl DisplayBackendDmabuf for GtkDisplayBackend {
fn import_dmabuf(&mut self, dmabuf_export: &DmabufExport) -> Result<u32, DisplayBackendError> {
let dmabuf_id = self.next_dmabuf_id;
self.next_dmabuf_id += 1;

self.channel
.send(DisplayEvent::ImportDmabuf {
dmabuf_id,
dmabuf_export: *dmabuf_export,
})
.unwrap();

Ok(dmabuf_id)
}

fn unref_dmabuf(&mut self, dmabuf_id: u32) -> Result<(), DisplayBackendError> {
self.channel
.send(DisplayEvent::UnrefDmabuf { dmabuf_id })
.unwrap();

Ok(())
}

fn configure_scanout_dmabuf(
&mut self,
scanout_id: u32,
display_width: u32,
display_height: u32,
dmabuf_id: u32,
src_rect: Option<&Rect>,
) -> Result<(), DisplayBackendError> {
let Some(scanout) = &mut self.scanouts[scanout_id as usize] else {
return Err(DisplayBackendError::InvalidScanoutId);
};

scanout.has_dmabuf = true;

self.channel
.send(DisplayEvent::ConfigureScanoutDmabuf {
scanout_id,
display_width,
display_height,
dmabuf_id,
src_rect: src_rect.copied(),
})
.unwrap();
Ok(())
}

fn present_dmabuf(
&mut self,
scanout_id: u32,
rect: Option<&Rect>,
) -> Result<(), DisplayBackendError> {
if self.scanouts[scanout_id as usize]
.as_ref()
.is_none_or(|scanout| !scanout.has_dmabuf)
{
return Err(DisplayBackendError::InvalidScanoutId);
};

let rect = rect.copied();
self.channel
.send(DisplayEvent::UpdateScanoutDmabuf { scanout_id, rect })
.unwrap();
Ok(())
}
}

fn resource_format_into_gdk(format: ResourceFormat) -> MemoryFormat {
match format {
ResourceFormat::BGRA => MemoryFormat::B8g8r8a8,
Expand All @@ -175,6 +274,8 @@ struct Scanout {
buffer_rx: Receiver<Vec<u8>>,
required_buffer_size: usize,
current_buffer: Vec<u8>,
#[cfg(target_os = "linux")]
has_dmabuf: bool,
}

impl Scanout {
Expand Down
Loading