11use crossbeam_channel:: { Receiver , Sender , TrySendError , bounded} ;
22use gtk:: { gdk:: MemoryFormat , glib:: Bytes } ;
33use 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 } ;
79use log:: error;
810use std:: mem;
911use utils:: pollable_channel:: PollableChannelSender ;
@@ -21,6 +23,15 @@ const _: () = {
2123
2224#[ derive( Debug , Clone ) ]
2325pub 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`
4468pub struct GtkDisplayBackend {
4569 channel : PollableChannelSender < DisplayEvent > ,
4670 scanouts : [ Option < Scanout > ; MAX_DISPLAYS ] ,
71+ #[ cfg( target_os = "linux" ) ]
72+ next_dmabuf_id : u32 ,
4773}
4874
4975impl 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+
160259fn 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
180281impl Scanout {
0 commit comments