Skip to content

Commit 4a66f1b

Browse files
committed
krun_gtk_display: Support importing and rendering dmabufs
Signed-off-by: Matej Hrica <mhrica@redhat.com>
1 parent 3809149 commit 4a66f1b

File tree

6 files changed

+476
-60
lines changed

6 files changed

+476
-60
lines changed

examples/krun_gtk_display/src/display_backend.rs

Lines changed: 108 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use crossbeam_channel::{Receiver, Sender, TrySendError, bounded};
22
use gtk::{gdk::MemoryFormat, glib::Bytes};
33
use krun_display::{
4-
DisplayBackendBasicFramebuffer, DisplayBackendError, DisplayBackendNew, MAX_DISPLAYS, Rect,
5-
ResourceFormat,
4+
DisplayBackendBasicFramebuffer, DisplayBackendError, DisplayBackendNew,
5+
MAX_DISPLAYS, Rect, ResourceFormat,
66
};
7+
#[cfg(target_os = "linux")]
8+
use krun_display::{DisplayBackendDmabuf, DmabufExport};
79
use log::error;
810
use std::mem;
911
use utils::pollable_channel::PollableChannelSender;
@@ -21,6 +23,15 @@ const _: () = {
2123

2224
#[derive(Debug, Clone)]
2325
pub enum DisplayEvent {
26+
#[cfg(target_os = "linux")]
27+
ImportDmabuf {
28+
dmabuf_id: u32,
29+
dmabuf_export: DmabufExport,
30+
},
31+
#[cfg(target_os = "linux")]
32+
UnrefDmabuf {
33+
dmabuf_id: u32,
34+
},
2435
ConfigureScanout {
2536
scanout_id: u32,
2637
display_width: u32,
@@ -29,6 +40,14 @@ pub enum DisplayEvent {
2940
height: u32,
3041
format: MemoryFormat,
3142
},
43+
#[cfg(target_os = "linux")]
44+
ConfigureScanoutDmabuf {
45+
scanout_id: u32,
46+
display_width: u32,
47+
display_height: u32,
48+
dmabuf_id: u32,
49+
src_rect: Option<Rect>,
50+
},
3251
DisableScanout {
3352
scanout_id: u32,
3453
},
@@ -37,24 +56,32 @@ pub enum DisplayEvent {
3756
buffer: Bytes,
3857
rect: Option<Rect>,
3958
},
59+
#[cfg(target_os = "linux")]
60+
UpdateScanoutDmabuf {
61+
scanout_id: u32,
62+
rect: Option<Rect>,
63+
},
4064
}
4165

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

4975
impl DisplayBackendNew<PollableChannelSender<DisplayEvent>> for GtkDisplayBackend {
50-
fn new(channel: Option<&PollableChannelSender<DisplayEvent>>) -> Self {
51-
let channel = channel
52-
.expect("The channel should have been set by GtkDisplayBackend::into_display_backend")
53-
.clone();
76+
fn new(userdata: Option<&PollableChannelSender<DisplayEvent>>) -> Self {
77+
let channel = userdata
78+
.expect("The userdata should have been set by GtkDisplayBackend::into_display_backend");
5479

5580
Self {
56-
channel,
81+
channel: channel.clone(),
5782
scanouts: Default::default(),
83+
#[cfg(target_os = "linux")]
84+
next_dmabuf_id: 1,
5885
}
5986
}
6087
}
@@ -89,6 +116,8 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
89116
buffer_rx,
90117
buffer_tx,
91118
current_buffer: Vec::new(),
119+
#[cfg(target_os = "linux")]
120+
has_dmabuf: false,
92121
});
93122
}
94123

@@ -157,6 +186,76 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
157186
}
158187
}
159188

189+
#[cfg(target_os = "linux")]
190+
impl DisplayBackendDmabuf for GtkDisplayBackend {
191+
fn import_dmabuf(&mut self, dmabuf_export: &DmabufExport) -> Result<u32, DisplayBackendError> {
192+
let dmabuf_id = self.next_dmabuf_id;
193+
self.next_dmabuf_id += 1;
194+
195+
self.channel
196+
.send(DisplayEvent::ImportDmabuf {
197+
dmabuf_id,
198+
dmabuf_export: *dmabuf_export,
199+
})
200+
.unwrap();
201+
202+
Ok(dmabuf_id)
203+
}
204+
205+
fn unref_dmabuf(&mut self, dmabuf_id: u32) -> Result<(), DisplayBackendError> {
206+
self.channel
207+
.send(DisplayEvent::UnrefDmabuf { dmabuf_id })
208+
.unwrap();
209+
210+
Ok(())
211+
}
212+
213+
fn configure_scanout_dmabuf(
214+
&mut self,
215+
scanout_id: u32,
216+
display_width: u32,
217+
display_height: u32,
218+
dmabuf_id: u32,
219+
src_rect: Option<&Rect>,
220+
) -> Result<(), DisplayBackendError> {
221+
let Some(scanout) = &mut self.scanouts[scanout_id as usize] else {
222+
return Err(DisplayBackendError::InvalidScanoutId);
223+
};
224+
225+
scanout.has_dmabuf = true;
226+
227+
self.channel
228+
.send(DisplayEvent::ConfigureScanoutDmabuf {
229+
scanout_id,
230+
display_width,
231+
display_height,
232+
dmabuf_id,
233+
src_rect: src_rect.copied(),
234+
})
235+
.unwrap();
236+
Ok(())
237+
}
238+
239+
fn present_dmabuf(
240+
&mut self,
241+
scanout_id: u32,
242+
rect: Option<&Rect>,
243+
) -> Result<(), DisplayBackendError> {
244+
if self.scanouts[scanout_id as usize]
245+
.as_ref()
246+
.is_none_or(|scanout| !scanout.has_dmabuf)
247+
{
248+
return Err(DisplayBackendError::InvalidScanoutId);
249+
};
250+
251+
let rect = rect.copied();
252+
self.channel
253+
.send(DisplayEvent::UpdateScanoutDmabuf { scanout_id, rect })
254+
.unwrap();
255+
Ok(())
256+
}
257+
}
258+
160259
fn resource_format_into_gdk(format: ResourceFormat) -> MemoryFormat {
161260
match format {
162261
ResourceFormat::BGRA => MemoryFormat::B8g8r8a8,
@@ -175,6 +274,8 @@ struct Scanout {
175274
buffer_rx: Receiver<Vec<u8>>,
176275
required_buffer_size: usize,
177276
current_buffer: Vec<u8>,
277+
#[cfg(target_os = "linux")]
278+
has_dmabuf: bool,
178279
}
179280

180281
impl Scanout {

0 commit comments

Comments
 (0)