1extern crate base;
8
9#[path = "dwl.rs"]
10#[allow(dead_code)]
11mod dwl;
12
13use std::cell::Cell;
14use std::cmp::max;
15use std::collections::HashMap;
16use std::ffi::CStr;
17use std::ffi::CString;
18use std::mem::zeroed;
19use std::panic::catch_unwind;
20use std::path::Path;
21use std::process::abort;
22use std::ptr::null;
23
24use anyhow::bail;
25use base::error;
26use base::round_up_to_page_size;
27use base::AsRawDescriptor;
28use base::MemoryMapping;
29use base::MemoryMappingBuilder;
30use base::RawDescriptor;
31use base::SharedMemory;
32use base::VolatileMemory;
33use dwl::*;
34use linux_input_sys::virtio_input_event;
35use sync::Waitable;
36use vm_control::gpu::DisplayParameters;
37
38use crate::DisplayExternalResourceImport;
39use crate::DisplayT;
40use crate::EventDeviceKind;
41use crate::FlipToExtraInfo;
42use crate::GpuDisplayError;
43use crate::GpuDisplayEvents;
44use crate::GpuDisplayFramebuffer;
45use crate::GpuDisplayResult;
46use crate::GpuDisplaySurface;
47use crate::SemaphoreTimepoint;
48use crate::SurfaceType;
49use crate::SysDisplayT;
50
51const BUFFER_COUNT: usize = 3;
52const BYTES_PER_PIXEL: u32 = 4;
53
54struct DwlContext(*mut dwl_context);
55impl Drop for DwlContext {
56 fn drop(&mut self) {
57 if !self.0.is_null() {
58 unsafe {
62 dwl_context_destroy(&mut self.0);
63 }
64 }
65 }
66}
67
68impl AsRawDescriptor for DwlContext {
69 fn as_raw_descriptor(&self) -> RawDescriptor {
70 unsafe { dwl_context_fd(self.0) }
73 }
74}
75
76struct DwlDmabuf(*mut dwl_dmabuf);
77
78impl Drop for DwlDmabuf {
79 fn drop(&mut self) {
80 if !self.0.is_null() {
81 unsafe {
85 dwl_dmabuf_destroy(&mut self.0);
86 }
87 }
88 }
89}
90
91struct DwlSurface(*mut dwl_surface);
92impl Drop for DwlSurface {
93 fn drop(&mut self) {
94 if !self.0.is_null() {
95 unsafe {
99 dwl_surface_destroy(&mut self.0);
100 }
101 }
102 }
103}
104
105struct WaylandSurface {
106 surface: DwlSurface,
107 row_size: u32,
108 buffer_size: usize,
109 buffer_index: Cell<usize>,
110 buffer_mem: MemoryMapping,
111}
112
113impl WaylandSurface {
114 fn surface(&self) -> *mut dwl_surface {
115 self.surface.0
116 }
117}
118
119impl GpuDisplaySurface for WaylandSurface {
120 fn surface_descriptor(&self) -> u64 {
121 let pointer = unsafe { dwl_surface_descriptor(self.surface.0) };
124 pointer as u64
125 }
126
127 fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
128 let buffer_index = (self.buffer_index.get() + 1) % BUFFER_COUNT;
129 let framebuffer = self
130 .buffer_mem
131 .get_slice(buffer_index * self.buffer_size, self.buffer_size)
132 .ok()?;
133
134 Some(GpuDisplayFramebuffer::new(
135 framebuffer,
136 self.row_size,
137 BYTES_PER_PIXEL,
138 ))
139 }
140
141 fn next_buffer_in_use(&self) -> bool {
142 let next_buffer_index = (self.buffer_index.get() + 1) % BUFFER_COUNT;
143 unsafe { dwl_surface_buffer_in_use(self.surface(), next_buffer_index) }
146 }
147
148 fn close_requested(&self) -> bool {
149 unsafe { dwl_surface_close_requested(self.surface()) }
152 }
153
154 fn flip(&mut self) {
155 self.buffer_index
156 .set((self.buffer_index.get() + 1) % BUFFER_COUNT);
157
158 unsafe {
161 dwl_surface_flip(self.surface(), self.buffer_index.get());
162 }
163 }
164
165 fn flip_to(
166 &mut self,
167 import_id: u32,
168 _acquire_timepoint: Option<SemaphoreTimepoint>,
169 _release_timepoint: Option<SemaphoreTimepoint>,
170 _extra_info: Option<FlipToExtraInfo>,
171 ) -> anyhow::Result<Waitable> {
172 unsafe { dwl_surface_flip_to(self.surface(), import_id) };
175 Ok(Waitable::signaled())
176 }
177
178 fn commit(&mut self) -> GpuDisplayResult<()> {
179 unsafe {
182 dwl_surface_commit(self.surface());
183 }
184
185 Ok(())
186 }
187
188 fn set_position(&mut self, x: u32, y: u32) {
189 unsafe {
192 dwl_surface_set_position(self.surface(), x, y);
193 }
194 }
195}
196
197pub struct DisplayWl {
202 dmabufs: HashMap<u32, DwlDmabuf>,
203 ctx: DwlContext,
204 current_event: Option<dwl_event>,
205 mt_tracking_id: u16,
206}
207
208#[allow(clippy::unnecessary_cast)]
214unsafe extern "C" fn error_callback(message: *const ::std::os::raw::c_char) {
215 catch_unwind(|| {
216 assert!(!message.is_null());
217 let msg = unsafe {
219 std::str::from_utf8(std::slice::from_raw_parts(
220 message as *const u8,
221 libc::strlen(message),
222 ))
223 .unwrap()
224 };
225 error!("{}", msg);
226 })
227 .unwrap_or_else(|_| abort())
228}
229
230impl DisplayWl {
231 pub fn new(wayland_path: Option<&Path>) -> GpuDisplayResult<DisplayWl> {
233 let ctx = DwlContext(unsafe { dwl_context_new(Some(error_callback)) });
236 if ctx.0.is_null() {
237 return Err(GpuDisplayError::Allocate);
238 }
239
240 let cstr_path = match wayland_path.map(|p| p.as_os_str().to_str()) {
243 Some(Some(s)) => match CString::new(s) {
244 Ok(cstr) => Some(cstr),
245 Err(_) => return Err(GpuDisplayError::InvalidPath),
246 },
247 Some(None) => return Err(GpuDisplayError::InvalidPath),
248 None => None,
249 };
250 let cstr_path_ptr = cstr_path
254 .as_ref()
255 .map(|s: &CString| CStr::as_ptr(s))
256 .unwrap_or(null());
257 let setup_success = unsafe { dwl_context_setup(ctx.0, cstr_path_ptr) };
259 if !setup_success {
260 return Err(GpuDisplayError::Connect);
261 }
262
263 Ok(DisplayWl {
264 dmabufs: HashMap::new(),
265 ctx,
266 current_event: None,
267 mt_tracking_id: 0u16,
268 })
269 }
270
271 fn ctx(&self) -> *mut dwl_context {
272 self.ctx.0
273 }
274
275 fn pop_event(&self) -> dwl_event {
276 unsafe {
279 let mut ev = zeroed();
280 dwl_context_next_event(self.ctx(), &mut ev);
281 ev
282 }
283 }
284
285 fn next_tracking_id(&mut self) -> i32 {
286 let cur_id: i32 = self.mt_tracking_id as i32;
287 self.mt_tracking_id = self.mt_tracking_id.wrapping_add(1);
288 cur_id
289 }
290
291 fn current_tracking_id(&self) -> i32 {
292 self.mt_tracking_id as i32
293 }
294}
295
296impl DisplayT for DisplayWl {
297 fn pending_events(&self) -> bool {
298 unsafe { dwl_context_pending_events(self.ctx()) }
301 }
302
303 fn next_event(&mut self) -> GpuDisplayResult<u64> {
304 let ev = self.pop_event();
305 let descriptor = ev.surface_descriptor as u64;
306 self.current_event = Some(ev);
307 Ok(descriptor)
308 }
309
310 fn handle_next_event(
311 &mut self,
312 _surface: &mut Box<dyn GpuDisplaySurface>,
313 ) -> Option<GpuDisplayEvents> {
314 let event = self.current_event.take().unwrap();
316
317 match event.event_type {
318 DWL_EVENT_TYPE_KEYBOARD_ENTER => None,
319 DWL_EVENT_TYPE_KEYBOARD_LEAVE => None,
320 DWL_EVENT_TYPE_KEYBOARD_KEY => {
321 let linux_keycode = event.params[0] as u16;
322 let pressed = event.params[1] == DWL_KEYBOARD_KEY_STATE_PRESSED;
323 let events = vec![virtio_input_event::key(linux_keycode, pressed, false)];
324 Some(GpuDisplayEvents {
325 events,
326 device_type: EventDeviceKind::Keyboard,
327 })
328 }
329 DWL_EVENT_TYPE_TOUCH_DOWN | DWL_EVENT_TYPE_TOUCH_MOTION => {
333 let tracking_id = if event.event_type == DWL_EVENT_TYPE_TOUCH_DOWN {
334 self.next_tracking_id()
335 } else {
336 self.current_tracking_id()
337 };
338
339 let events = vec![
340 virtio_input_event::multitouch_slot(0),
341 virtio_input_event::multitouch_tracking_id(tracking_id),
342 virtio_input_event::multitouch_absolute_x(max(0, event.params[0])),
343 virtio_input_event::multitouch_absolute_y(max(0, event.params[1])),
344 virtio_input_event::touch(true),
345 ];
346 Some(GpuDisplayEvents {
347 events,
348 device_type: EventDeviceKind::Touchscreen,
349 })
350 }
351 DWL_EVENT_TYPE_TOUCH_UP => {
352 let events = vec![
353 virtio_input_event::multitouch_slot(0),
354 virtio_input_event::multitouch_tracking_id(-1),
355 virtio_input_event::touch(false),
356 ];
357 Some(GpuDisplayEvents {
358 events,
359 device_type: EventDeviceKind::Touchscreen,
360 })
361 }
362 _ => {
363 error!("unknown event type {}", event.event_type);
364 None
365 }
366 }
367 }
368
369 fn flush(&self) {
370 unsafe {
373 dwl_context_dispatch(self.ctx());
374 }
375 }
376
377 fn create_surface(
378 &mut self,
379 parent_surface_id: Option<u32>,
380 surface_id: u32,
381 scanout_id: Option<u32>,
382 display_params: &DisplayParameters,
383 surf_type: SurfaceType,
384 ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>> {
385 let parent_id = parent_surface_id.unwrap_or(0);
386
387 let (width, height) = display_params.get_virtual_display_size();
388 let row_size = width * BYTES_PER_PIXEL;
389 let fb_size = row_size * height;
390 let buffer_size = round_up_to_page_size(fb_size as usize * BUFFER_COUNT);
391 let buffer_shm = SharedMemory::new("GpuDisplaySurface", buffer_size as u64)?;
392 let buffer_mem = MemoryMappingBuilder::new(buffer_size)
393 .from_shared_memory(&buffer_shm)
394 .build()
395 .unwrap();
396
397 let dwl_surf_flags = match surf_type {
398 SurfaceType::Cursor => DWL_SURFACE_FLAG_HAS_ALPHA,
399 SurfaceType::Scanout => DWL_SURFACE_FLAG_RECEIVE_INPUT,
400 };
401 let surface = DwlSurface(unsafe {
405 dwl_context_surface_new(
406 self.ctx(),
407 parent_id,
408 surface_id,
409 buffer_shm.as_raw_descriptor(),
410 buffer_size,
411 fb_size as usize,
412 width,
413 height,
414 row_size,
415 dwl_surf_flags,
416 )
417 });
418
419 if surface.0.is_null() {
420 return Err(GpuDisplayError::CreateSurface);
421 }
422
423 if let Some(scanout_id) = scanout_id {
424 unsafe {
427 dwl_surface_set_scanout_id(surface.0, scanout_id);
428 }
429 }
430
431 Ok(Box::new(WaylandSurface {
432 surface,
433 row_size,
434 buffer_size: fb_size as usize,
435 buffer_index: Cell::new(0),
436 buffer_mem,
437 }))
438 }
439
440 fn import_resource(
441 &mut self,
442 import_id: u32,
443 _surface_id: u32,
444 external_display_resource: DisplayExternalResourceImport,
445 ) -> anyhow::Result<()> {
446 #[allow(irrefutable_let_patterns)]
448 if let DisplayExternalResourceImport::Dmabuf {
449 descriptor,
450 offset,
451 stride,
452 modifiers,
453 width,
454 height,
455 fourcc,
456 } = external_display_resource
457 {
458 let dmabuf = DwlDmabuf(unsafe {
463 dwl_context_dmabuf_new(
464 self.ctx(),
465 import_id,
466 descriptor.as_raw_descriptor(),
467 offset,
468 stride,
469 modifiers,
470 width,
471 height,
472 fourcc,
473 )
474 });
475
476 if dmabuf.0.is_null() {
477 bail!("dmabuf import failed.");
478 }
479
480 self.dmabufs.insert(import_id, dmabuf);
481
482 Ok(())
483 } else {
484 bail!("gpu_display_wl only supports Dmabuf imports");
485 }
486 }
487
488 fn release_import(&mut self, _surface_id: u32, import_id: u32) {
489 self.dmabufs.remove(&import_id);
490 }
491}
492
493impl SysDisplayT for DisplayWl {}
494
495impl AsRawDescriptor for DisplayWl {
496 fn as_raw_descriptor(&self) -> RawDescriptor {
497 self.ctx.as_raw_descriptor()
499 }
500}