Skip to content

Commit d298903

Browse files
committed
krun_gtk_display: Support importing and rendering dmabufs
Signed-off-by: Matej Hrica <[email protected]>
1 parent 32ddba1 commit d298903

File tree

6 files changed

+421
-55
lines changed

6 files changed

+421
-55
lines changed

examples/krun_gtk_display/src/display_backend.rs

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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, DisplayBackendDmabuf, DisplayBackendError, DisplayBackendNew,
5+
DmabufExport, MAX_DISPLAYS, Rect, ResourceFormat,
66
};
77
use log::error;
88
use std::mem;
@@ -21,6 +21,13 @@ const _: () = {
2121

2222
#[derive(Debug, Clone)]
2323
pub enum DisplayEvent {
24+
ImportDmabuf {
25+
dmabuf_id: u32,
26+
dmabuf_export: DmabufExport,
27+
},
28+
UnrefDmabuf {
29+
dmabuf_id: u32,
30+
},
2431
ConfigureScanout {
2532
scanout_id: u32,
2633
display_width: u32,
@@ -29,6 +36,13 @@ pub enum DisplayEvent {
2936
height: u32,
3037
format: MemoryFormat,
3138
},
39+
ConfigureScanoutDmabuf {
40+
scanout_id: u32,
41+
display_width: u32,
42+
display_height: u32,
43+
dmabuf_id: u32,
44+
src_rect: Option<Rect>,
45+
},
3246
DisableScanout {
3347
scanout_id: u32,
3448
},
@@ -37,24 +51,29 @@ pub enum DisplayEvent {
3751
buffer: Bytes,
3852
rect: Option<Rect>,
3953
},
54+
UpdateScanoutDmabuf {
55+
scanout_id: u32,
56+
rect: Option<Rect>,
57+
},
4058
}
4159

4260
// Implements libkrun traits (callbacks) to provide a display implementation, by forwarding the
4361
// events to the `DisplayWorker`
4462
pub struct GtkDisplayBackend {
4563
channel: PollableChannelSender<DisplayEvent>,
4664
scanouts: [Option<Scanout>; MAX_DISPLAYS],
65+
next_dmabuf_id: u32,
4766
}
4867

4968
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();
69+
fn new(userdata: Option<&PollableChannelSender<DisplayEvent>>) -> Self {
70+
let channel = userdata
71+
.expect("The userdata should have been set by GtkDisplayBackend::into_display_backend");
5472

5573
Self {
56-
channel,
74+
channel: channel.clone(),
5775
scanouts: Default::default(),
76+
next_dmabuf_id: 1,
5877
}
5978
}
6079
}
@@ -89,6 +108,7 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
89108
buffer_rx,
90109
buffer_tx,
91110
current_buffer: Vec::new(),
111+
has_dmabuf: false,
92112
});
93113
}
94114

@@ -157,6 +177,75 @@ impl DisplayBackendBasicFramebuffer for GtkDisplayBackend {
157177
}
158178
}
159179

180+
impl DisplayBackendDmabuf for GtkDisplayBackend {
181+
fn import_dmabuf(&mut self, dmabuf_export: &DmabufExport) -> Result<u32, DisplayBackendError> {
182+
let dmabuf_id = self.next_dmabuf_id;
183+
self.next_dmabuf_id += 1;
184+
185+
self.channel
186+
.send(DisplayEvent::ImportDmabuf {
187+
dmabuf_id,
188+
dmabuf_export: *dmabuf_export,
189+
})
190+
.unwrap();
191+
192+
Ok(dmabuf_id)
193+
}
194+
195+
fn unref_dmabuf(&mut self, dmabuf_id: u32) -> Result<(), DisplayBackendError> {
196+
self.channel
197+
.send(DisplayEvent::UnrefDmabuf { dmabuf_id })
198+
.unwrap();
199+
200+
Ok(())
201+
}
202+
203+
fn configure_scanout_dmabuf(
204+
&mut self,
205+
scanout_id: u32,
206+
display_width: u32,
207+
display_height: u32,
208+
dmabuf_id: u32,
209+
src_rect: Option<&Rect>,
210+
) -> Result<(), DisplayBackendError> {
211+
let Some(scanout) = &mut self.scanouts[scanout_id as usize] else {
212+
return Err(DisplayBackendError::InvalidScanoutId);
213+
};
214+
215+
scanout.has_dmabuf = true;
216+
217+
self.channel
218+
.send(DisplayEvent::ConfigureScanoutDmabuf {
219+
scanout_id,
220+
display_width,
221+
display_height,
222+
dmabuf_id,
223+
src_rect: src_rect.copied(),
224+
})
225+
.unwrap();
226+
Ok(())
227+
}
228+
229+
fn present_dmabuf(
230+
&mut self,
231+
scanout_id: u32,
232+
rect: Option<&Rect>,
233+
) -> Result<(), DisplayBackendError> {
234+
if self.scanouts[scanout_id as usize]
235+
.as_ref()
236+
.is_none_or(|scanout| !scanout.has_dmabuf)
237+
{
238+
return Err(DisplayBackendError::InvalidScanoutId);
239+
};
240+
241+
let rect = rect.copied();
242+
self.channel
243+
.send(DisplayEvent::UpdateScanoutDmabuf { scanout_id, rect })
244+
.unwrap();
245+
Ok(())
246+
}
247+
}
248+
160249
fn resource_format_into_gdk(format: ResourceFormat) -> MemoryFormat {
161250
match format {
162251
ResourceFormat::BGRA => MemoryFormat::B8g8r8a8,
@@ -175,6 +264,7 @@ struct Scanout {
175264
buffer_rx: Receiver<Vec<u8>>,
176265
required_buffer_size: usize,
177266
current_buffer: Vec<u8>,
267+
has_dmabuf: bool,
178268
}
179269

180270
impl Scanout {

0 commit comments

Comments
 (0)