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