gpu_display/
lib.rs

1// Copyright 2018 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Crate for displaying simple surfaces and GPU buffers over a low-level display backend such as
6//! Wayland or X.
7
8use std::collections::BTreeMap;
9use std::io::Error as IoError;
10use std::time::Duration;
11
12use anyhow::anyhow;
13use anyhow::Context;
14use base::AsRawDescriptor;
15use base::Error as BaseError;
16use base::EventToken;
17use base::EventType;
18use base::VolatileSlice;
19use base::WaitContext;
20use remain::sorted;
21use rutabaga_gfx::AhbInfo;
22use serde::Deserialize;
23use serde::Serialize;
24use sync::Waitable;
25use thiserror::Error;
26use vm_control::gpu::DisplayParameters;
27use vm_control::gpu::MouseMode;
28#[cfg(feature = "vulkan_display")]
29use vulkano::VulkanLibrary;
30
31mod event_device;
32#[cfg(feature = "android_display")]
33mod gpu_display_android;
34#[cfg(feature = "android_display_stub")]
35mod gpu_display_android_stub;
36mod gpu_display_stub;
37#[cfg(windows)]
38mod gpu_display_win;
39#[cfg(any(target_os = "android", target_os = "linux"))]
40mod gpu_display_wl;
41#[cfg(feature = "x")]
42mod gpu_display_x;
43#[cfg(any(windows, feature = "x"))]
44mod keycode_converter;
45mod sys;
46#[cfg(feature = "vulkan_display")]
47pub mod vulkan;
48
49pub use event_device::EventDevice;
50pub use event_device::EventDeviceKind;
51#[cfg(windows)]
52pub use gpu_display_win::WindowProcedureThread;
53#[cfg(windows)]
54pub use gpu_display_win::WindowProcedureThreadBuilder;
55use linux_input_sys::virtio_input_event;
56use sys::SysDisplayT;
57pub use sys::SysGpuDisplayExt;
58
59// The number of bytes in a vulkan UUID.
60#[cfg(feature = "vulkan_display")]
61const VK_UUID_BYTES: usize = 16;
62
63#[derive(Clone)]
64pub struct VulkanCreateParams {
65    #[cfg(feature = "vulkan_display")]
66    pub vulkan_library: std::sync::Arc<VulkanLibrary>,
67    #[cfg(feature = "vulkan_display")]
68    pub device_uuid: [u8; VK_UUID_BYTES],
69    #[cfg(feature = "vulkan_display")]
70    pub driver_uuid: [u8; VK_UUID_BYTES],
71}
72
73/// An error generated by `GpuDisplay`.
74#[sorted]
75#[derive(Error, Debug)]
76pub enum GpuDisplayError {
77    /// An internal allocation failed.
78    #[error("internal allocation failed")]
79    Allocate,
80    /// A base error occurred.
81    #[error("received a base error: {0}")]
82    BaseError(BaseError),
83    /// Connecting to the compositor failed.
84    #[error("failed to connect to compositor")]
85    Connect,
86    /// Connection to compositor has been broken.
87    #[error("connection to compositor has been broken")]
88    ConnectionBroken,
89    /// Creating event file descriptor failed.
90    #[error("failed to create event file descriptor")]
91    CreateEvent,
92    /// Failed to create a surface on the compositor.
93    #[error("failed to crate surface on the compositor")]
94    CreateSurface,
95    /// Failed to import an event device.
96    #[error("failed to import an event device: {0}")]
97    FailedEventDeviceImport(String),
98    #[error("failed to register an event device to listen for guest events: {0}")]
99    FailedEventDeviceListen(base::TubeError),
100    /// Failed to import a buffer to the compositor.
101    #[error("failed to import a buffer to the compositor")]
102    FailedImport,
103    /// Android display service name is invalid.
104    #[error("invalid Android display service name: {0}")]
105    InvalidAndroidDisplayServiceName(String),
106    /// The import ID is invalid.
107    #[error("invalid import ID")]
108    InvalidImportId,
109    /// The path is invalid.
110    #[error("invalid path")]
111    InvalidPath,
112    /// The surface ID is invalid.
113    #[error("invalid surface ID")]
114    InvalidSurfaceId,
115    /// An input/output error occured.
116    #[error("an input/output error occur: {0}")]
117    IoError(IoError),
118    /// A required feature was missing.
119    #[error("required feature was missing: {0}")]
120    RequiredFeature(&'static str),
121    /// The method is unsupported by the implementation.
122    #[error("unsupported by the implementation")]
123    Unsupported,
124}
125
126pub type GpuDisplayResult<T> = std::result::Result<T, GpuDisplayError>;
127
128impl From<BaseError> for GpuDisplayError {
129    fn from(e: BaseError) -> GpuDisplayError {
130        GpuDisplayError::BaseError(e)
131    }
132}
133
134impl From<IoError> for GpuDisplayError {
135    fn from(e: IoError) -> GpuDisplayError {
136        GpuDisplayError::IoError(e)
137    }
138}
139
140/// A surface type
141#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
142pub enum SurfaceType {
143    /// Scanout surface
144    Scanout,
145    /// Mouse cursor surface
146    Cursor,
147}
148
149/// Event token for display instances
150#[derive(EventToken, Debug)]
151pub enum DisplayEventToken {
152    Display,
153    EventDevice { event_device_id: u32 },
154}
155
156#[derive(Clone)]
157pub struct GpuDisplayFramebuffer<'a> {
158    framebuffer: VolatileSlice<'a>,
159    slice: VolatileSlice<'a>,
160    stride: u32,
161    bytes_per_pixel: u32,
162}
163
164impl<'a> GpuDisplayFramebuffer<'a> {
165    fn new(
166        framebuffer: VolatileSlice<'a>,
167        stride: u32,
168        bytes_per_pixel: u32,
169    ) -> GpuDisplayFramebuffer<'a> {
170        GpuDisplayFramebuffer {
171            framebuffer,
172            slice: framebuffer,
173            stride,
174            bytes_per_pixel,
175        }
176    }
177
178    fn sub_region(
179        &self,
180        x: u32,
181        y: u32,
182        width: u32,
183        height: u32,
184    ) -> Option<GpuDisplayFramebuffer<'a>> {
185        let x_byte_offset = x.checked_mul(self.bytes_per_pixel)?;
186        let y_byte_offset = y.checked_mul(self.stride)?;
187        let byte_offset = x_byte_offset.checked_add(y_byte_offset)?;
188
189        let width_bytes = width.checked_mul(self.bytes_per_pixel)?;
190        let count = height
191            .checked_mul(self.stride)?
192            .checked_sub(self.stride)?
193            .checked_add(width_bytes)?;
194        let slice = self
195            .framebuffer
196            .sub_slice(byte_offset as usize, count as usize)
197            .unwrap();
198
199        Some(GpuDisplayFramebuffer { slice, ..*self })
200    }
201
202    pub fn as_volatile_slice(&self) -> VolatileSlice<'a> {
203        self.slice
204    }
205
206    pub fn stride(&self) -> u32 {
207        self.stride
208    }
209}
210
211trait GpuDisplaySurface {
212    /// Returns an unique ID associated with the surface.  This is typically generated by the
213    /// compositor or cast of a raw pointer.
214    fn surface_descriptor(&self) -> u64 {
215        0
216    }
217
218    /// Returns the next framebuffer, allocating if necessary.
219    fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
220        None
221    }
222
223    /// Returns true if the next buffer in the swapchain is already in use.
224    fn next_buffer_in_use(&self) -> bool {
225        false
226    }
227
228    /// Returns true if the surface should be closed.
229    fn close_requested(&self) -> bool {
230        false
231    }
232
233    /// Puts the next buffer on the screen, making it the current buffer.
234    fn flip(&mut self) {
235        // no-op
236    }
237
238    /// Puts the specified import_id on the screen.
239    fn flip_to(
240        &mut self,
241        _import_id: u32,
242        _acquire_timepoint: Option<SemaphoreTimepoint>,
243        _release_timepoint: Option<SemaphoreTimepoint>,
244        _extra_info: Option<FlipToExtraInfo>,
245    ) -> anyhow::Result<Waitable> {
246        // no-op
247        Ok(Waitable::signaled())
248    }
249
250    /// Commits the surface to the compositor.
251    fn commit(&mut self) -> GpuDisplayResult<()> {
252        Ok(())
253    }
254
255    /// Sets the mouse mode used on this surface.
256    fn set_mouse_mode(&mut self, _mouse_mode: MouseMode) {
257        // no-op
258    }
259
260    /// Sets the position of the identified subsurface relative to its parent.
261    fn set_position(&mut self, _x: u32, _y: u32) {
262        // no-op
263    }
264
265    /// Returns the type of the completed buffer.
266    #[allow(dead_code)]
267    fn buffer_completion_type(&self) -> u32 {
268        0
269    }
270
271    /// Draws the current buffer on the screen.
272    #[allow(dead_code)]
273    fn draw_current_buffer(&mut self) {
274        // no-op
275    }
276
277    /// Handles a compositor-specific client event.
278    #[allow(dead_code)]
279    fn on_client_message(&mut self, _client_data: u64) {
280        // no-op
281    }
282
283    /// Handles a compositor-specific shared memory completion event.
284    #[allow(dead_code)]
285    fn on_shm_completion(&mut self, _shm_complete: u64) {
286        // no-op
287    }
288}
289
290struct GpuDisplayEvents {
291    events: Vec<virtio_input_event>,
292    device_type: EventDeviceKind,
293}
294
295trait DisplayT: AsRawDescriptor {
296    /// Returns true if there are events that are on the queue.
297    fn pending_events(&self) -> bool {
298        false
299    }
300
301    /// Sends any pending commands to the compositor.
302    fn flush(&self) {
303        // no-op
304    }
305
306    /// Returns the surface descirptor associated with the current event
307    fn next_event(&mut self) -> GpuDisplayResult<u64> {
308        Ok(0)
309    }
310
311    /// Handles the event from the compositor, and returns an list of events
312    fn handle_next_event(
313        &mut self,
314        _surface: &mut Box<dyn GpuDisplaySurface>,
315    ) -> Option<GpuDisplayEvents> {
316        None
317    }
318
319    /// Creates a surface with the given parameters.  The display backend is given a non-zero
320    /// `surface_id` as a handle for subsequent operations.
321    fn create_surface(
322        &mut self,
323        parent_surface_id: Option<u32>,
324        surface_id: u32,
325        scanout_id: Option<u32>,
326        display_params: &DisplayParameters,
327        surf_type: SurfaceType,
328    ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>;
329
330    /// Imports a resource into the display backend.  The display backend is given a non-zero
331    /// `import_id` as a handle for subsequent operations.
332    fn import_resource(
333        &mut self,
334        _import_id: u32,
335        _surface_id: u32,
336        _external_display_resource: DisplayExternalResourceImport,
337    ) -> anyhow::Result<()> {
338        Err(anyhow!("import_resource is unsupported"))
339    }
340
341    /// Frees a previously imported resource.
342    fn release_import(&mut self, _import_id: u32, _surface_id: u32) {}
343
344    /// Releases a previously created surface.
345    fn release_surface(&mut self, _surface_id: u32) {}
346}
347
348pub trait GpuDisplayExt {
349    /// Imports the given `event_device` into the display, returning an event device id on success.
350    /// This device may be used to dispatch input events to the guest.
351    fn import_event_device(&mut self, event_device: EventDevice) -> GpuDisplayResult<u32>;
352
353    /// Called when an event device is readable.
354    fn handle_event_device(&mut self, event_device_id: u32);
355}
356
357pub enum DisplayExternalResourceImport<'a> {
358    Dmabuf {
359        descriptor: &'a dyn AsRawDescriptor,
360        offset: u32,
361        stride: u32,
362        modifiers: u64,
363        width: u32,
364        height: u32,
365        fourcc: u32,
366    },
367    VulkanImage {
368        descriptor: &'a dyn AsRawDescriptor,
369        metadata: VulkanDisplayImageImportMetadata,
370    },
371    VulkanTimelineSemaphore {
372        descriptor: &'a dyn AsRawDescriptor,
373    },
374    AHardwareBuffer {
375        info: AhbInfo,
376    },
377}
378
379pub struct VkExtent3D {
380    pub width: u32,
381    pub height: u32,
382    pub depth: u32,
383}
384
385pub struct VulkanDisplayImageImportMetadata {
386    // These fields go into a VkImageCreateInfo
387    pub flags: u32,
388    pub image_type: i32,
389    pub format: i32,
390    pub extent: VkExtent3D,
391    pub mip_levels: u32,
392    pub array_layers: u32,
393    pub samples: u32,
394    pub tiling: i32,
395    pub usage: u32,
396    pub sharing_mode: i32,
397    pub queue_family_indices: Vec<u32>,
398    pub initial_layout: i32,
399
400    // These fields go into a VkMemoryAllocateInfo
401    pub allocation_size: u64,
402    pub memory_type_index: u32,
403
404    // Additional information
405    pub dedicated_allocation: bool,
406}
407
408pub struct SemaphoreTimepoint {
409    pub import_id: u32,
410    pub value: u64,
411}
412
413pub enum FlipToExtraInfo {
414    #[cfg(feature = "vulkan_display")]
415    Vulkan { old_layout: i32, new_layout: i32 },
416}
417
418/// A connection to the compositor and associated collection of state.
419///
420/// The user of `GpuDisplay` can use `AsRawDescriptor` to poll on the compositor connection's file
421/// descriptor. When the connection is readable, `dispatch_events` can be called to process it.
422pub struct GpuDisplay {
423    next_id: u32,
424    event_devices: BTreeMap<u32, EventDevice>,
425    surfaces: BTreeMap<u32, Box<dyn GpuDisplaySurface>>,
426    wait_ctx: WaitContext<DisplayEventToken>,
427    // `inner` must be after `surfaces` to ensure those objects are dropped before
428    // the display context. The drop order for fields inside a struct is the order in which they
429    // are declared [Rust RFC 1857].
430    //
431    // We also don't want to drop inner before wait_ctx because it contains references to the event
432    // devices owned by inner.display_event_dispatcher.
433    inner: Box<dyn SysDisplayT>,
434}
435
436impl GpuDisplay {
437    /// Opens a connection to X server
438    pub fn open_x(display_name: Option<&str>) -> GpuDisplayResult<GpuDisplay> {
439        let _ = display_name;
440        #[cfg(feature = "x")]
441        {
442            let display = gpu_display_x::DisplayX::open_display(display_name)?;
443
444            let wait_ctx = WaitContext::new()?;
445            wait_ctx.add(&display, DisplayEventToken::Display)?;
446
447            Ok(GpuDisplay {
448                inner: Box::new(display),
449                next_id: 1,
450                event_devices: Default::default(),
451                surfaces: Default::default(),
452                wait_ctx,
453            })
454        }
455        #[cfg(not(feature = "x"))]
456        Err(GpuDisplayError::Unsupported)
457    }
458
459    pub fn open_android(service_name: &str) -> GpuDisplayResult<GpuDisplay> {
460        let _ = service_name;
461        #[cfg(feature = "android_display")]
462        {
463            let display = gpu_display_android::DisplayAndroid::new(service_name)?;
464
465            let wait_ctx = WaitContext::new()?;
466            wait_ctx.add(&display, DisplayEventToken::Display)?;
467
468            Ok(GpuDisplay {
469                inner: Box::new(display),
470                next_id: 1,
471                event_devices: Default::default(),
472                surfaces: Default::default(),
473                wait_ctx,
474            })
475        }
476        #[cfg(not(feature = "android_display"))]
477        Err(GpuDisplayError::Unsupported)
478    }
479
480    pub fn open_stub() -> GpuDisplayResult<GpuDisplay> {
481        let display = gpu_display_stub::DisplayStub::new()?;
482        let wait_ctx = WaitContext::new()?;
483        wait_ctx.add(&display, DisplayEventToken::Display)?;
484
485        Ok(GpuDisplay {
486            inner: Box::new(display),
487            next_id: 1,
488            event_devices: Default::default(),
489            surfaces: Default::default(),
490            wait_ctx,
491        })
492    }
493
494    // Leaves the `GpuDisplay` in a undefined state.
495    //
496    // TODO: Would be nice to change receiver from `&mut self` to `self`. Requires some refactoring
497    // elsewhere.
498    pub fn take_event_devices(&mut self) -> Vec<EventDevice> {
499        std::mem::take(&mut self.event_devices)
500            .into_values()
501            .collect()
502    }
503
504    fn dispatch_display_events(&mut self) -> GpuDisplayResult<()> {
505        self.inner.flush();
506        while self.inner.pending_events() {
507            let surface_descriptor = self.inner.next_event()?;
508
509            for surface in self.surfaces.values_mut() {
510                if surface_descriptor != surface.surface_descriptor() {
511                    continue;
512                }
513
514                if let Some(gpu_display_events) = self.inner.handle_next_event(surface) {
515                    for event_device in self.event_devices.values_mut() {
516                        if event_device.kind() != gpu_display_events.device_type {
517                            continue;
518                        }
519
520                        event_device.send_report(gpu_display_events.events.iter().cloned())?;
521                    }
522                }
523            }
524        }
525
526        Ok(())
527    }
528
529    /// Dispatches internal events that were received from the compositor since the last call to
530    /// `dispatch_events`.
531    pub fn dispatch_events(&mut self) -> GpuDisplayResult<()> {
532        let wait_events = self.wait_ctx.wait_timeout(Duration::default())?;
533
534        if let Some(wait_event) = wait_events.iter().find(|e| e.is_hungup) {
535            base::error!(
536                "Display signaled with a hungup event for token {:?}",
537                wait_event.token
538            );
539            self.wait_ctx = WaitContext::new().unwrap();
540            return GpuDisplayResult::Err(GpuDisplayError::ConnectionBroken);
541        }
542
543        for wait_event in wait_events.iter().filter(|e| e.is_writable) {
544            if let DisplayEventToken::EventDevice { event_device_id } = wait_event.token {
545                if let Some(event_device) = self.event_devices.get_mut(&event_device_id) {
546                    if !event_device.flush_buffered_events()? {
547                        continue;
548                    }
549                    self.wait_ctx.modify(
550                        event_device,
551                        EventType::Read,
552                        DisplayEventToken::EventDevice { event_device_id },
553                    )?;
554                }
555            }
556        }
557
558        for wait_event in wait_events.iter().filter(|e| e.is_readable) {
559            match wait_event.token {
560                DisplayEventToken::Display => self.dispatch_display_events()?,
561                DisplayEventToken::EventDevice { event_device_id } => {
562                    self.handle_event_device(event_device_id)
563                }
564            }
565        }
566
567        Ok(())
568    }
569
570    /// Creates a surface on the the compositor as either a top level window, or child of another
571    /// surface, returning a handle to the new surface.
572    pub fn create_surface(
573        &mut self,
574        parent_surface_id: Option<u32>,
575        scanout_id: Option<u32>,
576        display_params: &DisplayParameters,
577        surf_type: SurfaceType,
578    ) -> GpuDisplayResult<u32> {
579        if let Some(parent_id) = parent_surface_id {
580            if !self.surfaces.contains_key(&parent_id) {
581                return Err(GpuDisplayError::InvalidSurfaceId);
582            }
583        }
584
585        let new_surface_id = self.next_id;
586        let new_surface = self.inner.create_surface(
587            parent_surface_id,
588            new_surface_id,
589            scanout_id,
590            display_params,
591            surf_type,
592        )?;
593
594        self.next_id += 1;
595        self.surfaces.insert(new_surface_id, new_surface);
596        Ok(new_surface_id)
597    }
598
599    /// Releases a previously created surface identified by the given handle.
600    pub fn release_surface(&mut self, surface_id: u32) {
601        self.surfaces.remove(&surface_id);
602        self.inner.release_surface(surface_id);
603    }
604
605    /// Gets a reference to an unused framebuffer for the identified surface.
606    pub fn framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer> {
607        let surface = self.surfaces.get_mut(&surface_id)?;
608        surface.framebuffer()
609    }
610
611    /// Gets a reference to an unused framebuffer for the identified surface.
612    pub fn framebuffer_region(
613        &mut self,
614        surface_id: u32,
615        x: u32,
616        y: u32,
617        width: u32,
618        height: u32,
619    ) -> Option<GpuDisplayFramebuffer> {
620        let framebuffer = self.framebuffer(surface_id)?;
621        framebuffer.sub_region(x, y, width, height)
622    }
623
624    /// Returns true if the next buffer in the buffer queue for the given surface is currently in
625    /// use.
626    ///
627    /// If the next buffer is in use, the memory returned from `framebuffer_memory` should not be
628    /// written to.
629    pub fn next_buffer_in_use(&self, surface_id: u32) -> bool {
630        self.surfaces
631            .get(&surface_id)
632            .map(|s| s.next_buffer_in_use())
633            .unwrap_or(false)
634    }
635
636    /// Changes the visible contents of the identified surface to the contents of the framebuffer
637    /// last returned by `framebuffer_memory` for this surface.
638    pub fn flip(&mut self, surface_id: u32) {
639        if let Some(surface) = self.surfaces.get_mut(&surface_id) {
640            surface.flip()
641        }
642    }
643
644    /// Returns true if the identified top level surface has been told to close by the compositor,
645    /// and by extension the user.
646    pub fn close_requested(&self, surface_id: u32) -> bool {
647        self.surfaces
648            .get(&surface_id)
649            .map(|s| s.close_requested())
650            .unwrap_or(true)
651    }
652
653    /// Imports a resource to the display backend. This resource may be an image for the compositor
654    /// or a synchronization object.
655    pub fn import_resource(
656        &mut self,
657        surface_id: u32,
658        external_display_resource: DisplayExternalResourceImport,
659    ) -> anyhow::Result<u32> {
660        let import_id = self.next_id;
661
662        self.inner
663            .import_resource(import_id, surface_id, external_display_resource)?;
664
665        self.next_id += 1;
666        Ok(import_id)
667    }
668
669    /// Releases a previously imported resource identified by the given handle.
670    pub fn release_import(&mut self, import_id: u32, surface_id: u32) {
671        self.inner.release_import(import_id, surface_id);
672    }
673
674    /// Commits any pending state for the identified surface.
675    pub fn commit(&mut self, surface_id: u32) -> GpuDisplayResult<()> {
676        let surface = self
677            .surfaces
678            .get_mut(&surface_id)
679            .ok_or(GpuDisplayError::InvalidSurfaceId)?;
680
681        surface.commit()
682    }
683
684    /// Changes the visible contents of the identified surface to that of the identified imported
685    /// buffer.
686    pub fn flip_to(
687        &mut self,
688        surface_id: u32,
689        import_id: u32,
690        acquire_timepoint: Option<SemaphoreTimepoint>,
691        release_timepoint: Option<SemaphoreTimepoint>,
692        extra_info: Option<FlipToExtraInfo>,
693    ) -> anyhow::Result<Waitable> {
694        let surface = self
695            .surfaces
696            .get_mut(&surface_id)
697            .ok_or(GpuDisplayError::InvalidSurfaceId)?;
698
699        surface
700            .flip_to(import_id, acquire_timepoint, release_timepoint, extra_info)
701            .context("failed in flip on GpuDisplaySurface")
702    }
703
704    /// Sets the mouse mode used on this surface.
705    pub fn set_mouse_mode(
706        &mut self,
707        surface_id: u32,
708        mouse_mode: MouseMode,
709    ) -> GpuDisplayResult<()> {
710        let surface = self
711            .surfaces
712            .get_mut(&surface_id)
713            .ok_or(GpuDisplayError::InvalidSurfaceId)?;
714
715        surface.set_mouse_mode(mouse_mode);
716        Ok(())
717    }
718
719    /// Sets the position of the identified subsurface relative to its parent.
720    ///
721    /// The change in position will not be visible until `commit` is called for the parent surface.
722    pub fn set_position(&mut self, surface_id: u32, x: u32, y: u32) -> GpuDisplayResult<()> {
723        let surface = self
724            .surfaces
725            .get_mut(&surface_id)
726            .ok_or(GpuDisplayError::InvalidSurfaceId)?;
727
728        surface.set_position(x, y);
729        Ok(())
730    }
731}