• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 use std::collections::BTreeMap;
9 use std::io::Error as IoError;
10 use std::time::Duration;
11 
12 use base::AsRawDescriptor;
13 use base::Error as BaseError;
14 use base::EventToken;
15 use base::EventType;
16 use base::WaitContext;
17 use data_model::VolatileSlice;
18 use remain::sorted;
19 use thiserror::Error;
20 
21 mod event_device;
22 mod gpu_display_stub;
23 #[cfg(windows)]
24 mod gpu_display_win;
25 #[cfg(unix)]
26 mod gpu_display_wl;
27 #[cfg(feature = "x")]
28 mod gpu_display_x;
29 #[cfg(feature = "x")]
30 mod keycode_converter;
31 mod sys;
32 
33 pub use event_device::EventDevice;
34 pub use event_device::EventDeviceKind;
35 #[cfg(windows)]
36 pub use gpu_display_win::DisplayProperties as WinDisplayProperties;
37 use linux_input_sys::virtio_input_event;
38 use sys::SysDisplayT;
39 pub use sys::SysGpuDisplayExt;
40 #[cfg(windows)]
41 pub type WindowProcedureThread = gpu_display_win::WindowProcedureThread<gpu_display_win::Surface>;
42 
43 /// An error generated by `GpuDisplay`.
44 #[sorted]
45 #[derive(Error, Debug)]
46 pub enum GpuDisplayError {
47     /// An internal allocation failed.
48     #[error("internal allocation failed")]
49     Allocate,
50     /// A base error occurred.
51     #[error("received a base error: {0}")]
52     BaseError(BaseError),
53     /// Connecting to the compositor failed.
54     #[error("failed to connect to compositor")]
55     Connect,
56     /// Connection to compositor has been broken.
57     #[error("connection to compositor has been broken")]
58     ConnectionBroken,
59     /// Creating event file descriptor failed.
60     #[error("failed to create event file descriptor")]
61     CreateEvent,
62     /// Failed to create a surface on the compositor.
63     #[error("failed to crate surface on the compositor")]
64     CreateSurface,
65     /// Failed to import an event device.
66     #[error("failed to import an event device: {0}")]
67     FailedEventDeviceImport(String),
68     /// Failed to import a buffer to the compositor.
69     #[error("failed to import a buffer to the compositor")]
70     FailedImport,
71     /// The import ID is invalid.
72     #[error("invalid import ID")]
73     InvalidImportId,
74     /// The path is invalid.
75     #[error("invalid path")]
76     InvalidPath,
77     /// The surface ID is invalid.
78     #[error("invalid surface ID")]
79     InvalidSurfaceId,
80     /// An input/output error occured.
81     #[error("an input/output error occur: {0}")]
82     IoError(IoError),
83     /// A required feature was missing.
84     #[error("required feature was missing: {0}")]
85     RequiredFeature(&'static str),
86     /// The method is unsupported by the implementation.
87     #[error("unsupported by the implementation")]
88     Unsupported,
89 }
90 
91 pub type GpuDisplayResult<T> = std::result::Result<T, GpuDisplayError>;
92 
93 impl From<BaseError> for GpuDisplayError {
from(e: BaseError) -> GpuDisplayError94     fn from(e: BaseError) -> GpuDisplayError {
95         GpuDisplayError::BaseError(e)
96     }
97 }
98 
99 impl From<IoError> for GpuDisplayError {
from(e: IoError) -> GpuDisplayError100     fn from(e: IoError) -> GpuDisplayError {
101         GpuDisplayError::IoError(e)
102     }
103 }
104 
105 /// A surface type
106 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
107 pub enum SurfaceType {
108     /// Scanout surface
109     Scanout,
110     /// Mouse cursor surface
111     Cursor,
112 }
113 
114 /// Event token for display instances
115 #[derive(EventToken, Debug)]
116 pub enum DisplayEventToken {
117     Display,
118     EventDevice { event_device_id: u32 },
119 }
120 
121 #[derive(Clone)]
122 pub struct GpuDisplayFramebuffer<'a> {
123     framebuffer: VolatileSlice<'a>,
124     slice: VolatileSlice<'a>,
125     stride: u32,
126     bytes_per_pixel: u32,
127 }
128 
129 impl<'a> GpuDisplayFramebuffer<'a> {
new( framebuffer: VolatileSlice<'a>, stride: u32, bytes_per_pixel: u32, ) -> GpuDisplayFramebuffer130     fn new(
131         framebuffer: VolatileSlice<'a>,
132         stride: u32,
133         bytes_per_pixel: u32,
134     ) -> GpuDisplayFramebuffer {
135         GpuDisplayFramebuffer {
136             framebuffer,
137             slice: framebuffer,
138             stride,
139             bytes_per_pixel,
140         }
141     }
142 
sub_region( &self, x: u32, y: u32, width: u32, height: u32, ) -> Option<GpuDisplayFramebuffer<'a>>143     fn sub_region(
144         &self,
145         x: u32,
146         y: u32,
147         width: u32,
148         height: u32,
149     ) -> Option<GpuDisplayFramebuffer<'a>> {
150         let x_byte_offset = x.checked_mul(self.bytes_per_pixel)?;
151         let y_byte_offset = y.checked_mul(self.stride)?;
152         let byte_offset = x_byte_offset.checked_add(y_byte_offset)?;
153 
154         let width_bytes = width.checked_mul(self.bytes_per_pixel)?;
155         let count = height
156             .checked_mul(self.stride)?
157             .checked_sub(self.stride)?
158             .checked_add(width_bytes)?;
159         let slice = self
160             .framebuffer
161             .sub_slice(byte_offset as usize, count as usize)
162             .unwrap();
163 
164         Some(GpuDisplayFramebuffer { slice, ..*self })
165     }
166 
as_volatile_slice(&self) -> VolatileSlice<'a>167     pub fn as_volatile_slice(&self) -> VolatileSlice<'a> {
168         self.slice
169     }
170 
stride(&self) -> u32171     pub fn stride(&self) -> u32 {
172         self.stride
173     }
174 }
175 
176 /// Empty trait, just used as a bounds for now
177 trait GpuDisplayImport {}
178 
179 trait GpuDisplaySurface {
180     /// Returns an unique ID associated with the surface.  This is typically generated by the
181     /// compositor or cast of a raw pointer.
surface_descriptor(&self) -> u64182     fn surface_descriptor(&self) -> u64 {
183         0
184     }
185 
186     /// Returns the next framebuffer, allocating if necessary.
framebuffer(&mut self) -> Option<GpuDisplayFramebuffer>187     fn framebuffer(&mut self) -> Option<GpuDisplayFramebuffer> {
188         None
189     }
190 
191     /// Returns true if the next buffer in the swapchain is already in use.
next_buffer_in_use(&self) -> bool192     fn next_buffer_in_use(&self) -> bool {
193         false
194     }
195 
196     /// Returns true if the surface should be closed.
close_requested(&self) -> bool197     fn close_requested(&self) -> bool {
198         false
199     }
200 
201     /// Puts the next buffer on the screen, making it the current buffer.
flip(&mut self)202     fn flip(&mut self) {
203         // no-op
204     }
205 
206     /// Puts the specified import_id on the screen.
flip_to(&mut self, _import_id: u32)207     fn flip_to(&mut self, _import_id: u32) {
208         // no-op
209     }
210 
211     /// Commits the surface to the compositor.
commit(&mut self) -> GpuDisplayResult<()>212     fn commit(&mut self) -> GpuDisplayResult<()> {
213         Ok(())
214     }
215 
216     /// Sets the position of the identified subsurface relative to its parent.
set_position(&mut self, _x: u32, _y: u32)217     fn set_position(&mut self, _x: u32, _y: u32) {
218         // no-op
219     }
220 
221     /// Returns the type of the completed buffer.
buffer_completion_type(&self) -> u32222     fn buffer_completion_type(&self) -> u32 {
223         0
224     }
225 
226     /// Draws the current buffer on the screen.
draw_current_buffer(&mut self)227     fn draw_current_buffer(&mut self) {
228         // no-op
229     }
230 
231     /// Handles a compositor-specific client event.
on_client_message(&mut self, _client_data: u64)232     fn on_client_message(&mut self, _client_data: u64) {
233         // no-op
234     }
235 
236     /// Handles a compositor-specific shared memory completion event.
on_shm_completion(&mut self, _shm_complete: u64)237     fn on_shm_completion(&mut self, _shm_complete: u64) {
238         // no-op
239     }
240 
241     /// Sets the scanout ID for the surface.
set_scanout_id(&mut self, _scanout_id: u32)242     fn set_scanout_id(&mut self, _scanout_id: u32) {
243         // no-op
244     }
245 }
246 
247 struct GpuDisplayEvents {
248     events: Vec<virtio_input_event>,
249     device_type: EventDeviceKind,
250 }
251 
252 trait DisplayT: AsRawDescriptor {
253     /// Returns true if there are events that are on the queue.
pending_events(&self) -> bool254     fn pending_events(&self) -> bool {
255         false
256     }
257 
258     /// Sends any pending commands to the compositor.
flush(&self)259     fn flush(&self) {
260         // no-op
261     }
262 
263     /// Returns the surface descirptor associated with the current event
next_event(&mut self) -> GpuDisplayResult<u64>264     fn next_event(&mut self) -> GpuDisplayResult<u64> {
265         Ok(0)
266     }
267 
268     /// Handles the event from the compositor, and returns an list of events
handle_next_event( &mut self, _surface: &mut Box<dyn GpuDisplaySurface>, ) -> Option<GpuDisplayEvents>269     fn handle_next_event(
270         &mut self,
271         _surface: &mut Box<dyn GpuDisplaySurface>,
272     ) -> Option<GpuDisplayEvents> {
273         None
274     }
275 
276     /// Creates a surface with the given parameters.  The display backend is given a non-zero
277     /// `surface_id` as a handle for subsequent operations.
create_surface( &mut self, parent_surface_id: Option<u32>, surface_id: u32, width: u32, height: u32, surf_type: SurfaceType, ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>278     fn create_surface(
279         &mut self,
280         parent_surface_id: Option<u32>,
281         surface_id: u32,
282         width: u32,
283         height: u32,
284         surf_type: SurfaceType,
285     ) -> GpuDisplayResult<Box<dyn GpuDisplaySurface>>;
286 
287     /// Imports memory into the display backend.  The display backend is given a non-zero
288     /// `import_id` as a handle for subsequent operations.
import_memory( &mut self, _import_id: u32, _descriptor: &dyn AsRawDescriptor, _offset: u32, _stride: u32, _modifiers: u64, _width: u32, _height: u32, _fourcc: u32, ) -> GpuDisplayResult<Box<dyn GpuDisplayImport>>289     fn import_memory(
290         &mut self,
291         _import_id: u32,
292         _descriptor: &dyn AsRawDescriptor,
293         _offset: u32,
294         _stride: u32,
295         _modifiers: u64,
296         _width: u32,
297         _height: u32,
298         _fourcc: u32,
299     ) -> GpuDisplayResult<Box<dyn GpuDisplayImport>> {
300         Err(GpuDisplayError::Unsupported)
301     }
302 }
303 
304 pub trait GpuDisplayExt {
305     /// Imports the given `event_device` into the display, returning an event device id on success.
306     /// This device may be used to poll for input events.
import_event_device(&mut self, event_device: EventDevice) -> GpuDisplayResult<u32>307     fn import_event_device(&mut self, event_device: EventDevice) -> GpuDisplayResult<u32>;
308 }
309 
310 /// A connection to the compositor and associated collection of state.
311 ///
312 /// The user of `GpuDisplay` can use `AsRawDescriptor` to poll on the compositor connection's file
313 /// descriptor. When the connection is readable, `dispatch_events` can be called to process it.
314 pub struct GpuDisplay {
315     next_id: u32,
316     event_devices: BTreeMap<u32, EventDevice>,
317     surfaces: BTreeMap<u32, Box<dyn GpuDisplaySurface>>,
318     imports: BTreeMap<u32, Box<dyn GpuDisplayImport>>,
319     // `inner` must be after `imports` and `surfaces` to ensure those objects are dropped before
320     // the display context. The drop order for fields inside a struct is the order in which they
321     // are declared [Rust RFC 1857].
322     inner: Box<dyn SysDisplayT>,
323     wait_ctx: WaitContext<DisplayEventToken>,
324     is_x: bool,
325 }
326 
327 impl GpuDisplay {
328     /// Opens a connection to X server
open_x<S: AsRef<str>>(display_name: Option<S>) -> GpuDisplayResult<GpuDisplay>329     pub fn open_x<S: AsRef<str>>(display_name: Option<S>) -> GpuDisplayResult<GpuDisplay> {
330         let _ = display_name;
331         #[cfg(feature = "x")]
332         {
333             let display = match display_name {
334                 Some(s) => gpu_display_x::DisplayX::open_display(Some(s.as_ref()))?,
335                 None => gpu_display_x::DisplayX::open_display(None)?,
336             };
337 
338             let wait_ctx = WaitContext::new()?;
339             wait_ctx.add(&display, DisplayEventToken::Display)?;
340 
341             Ok(GpuDisplay {
342                 inner: Box::new(display),
343                 next_id: 1,
344                 event_devices: Default::default(),
345                 surfaces: Default::default(),
346                 imports: Default::default(),
347                 wait_ctx,
348                 is_x: true,
349             })
350         }
351         #[cfg(not(feature = "x"))]
352         Err(GpuDisplayError::Unsupported)
353     }
354 
open_stub() -> GpuDisplayResult<GpuDisplay>355     pub fn open_stub() -> GpuDisplayResult<GpuDisplay> {
356         let display = gpu_display_stub::DisplayStub::new()?;
357         let wait_ctx = WaitContext::new()?;
358         wait_ctx.add(&display, DisplayEventToken::Display)?;
359 
360         Ok(GpuDisplay {
361             inner: Box::new(display),
362             next_id: 1,
363             event_devices: Default::default(),
364             surfaces: Default::default(),
365             imports: Default::default(),
366             wait_ctx,
367             is_x: false,
368         })
369     }
370 
371     /// Return whether this display is an X display
is_x(&self) -> bool372     pub fn is_x(&self) -> bool {
373         self.is_x
374     }
375 
handle_event_device(&mut self, event_device_id: u32)376     fn handle_event_device(&mut self, event_device_id: u32) {
377         if let Some(event_device) = self.event_devices.get(&event_device_id) {
378             // TODO(zachr): decode the event and forward to the device.
379             let _ = event_device.recv_event_encoded();
380         }
381     }
382 
dispatch_display_events(&mut self) -> GpuDisplayResult<()>383     fn dispatch_display_events(&mut self) -> GpuDisplayResult<()> {
384         self.inner.flush();
385         while self.inner.pending_events() {
386             let surface_descriptor = self.inner.next_event()?;
387 
388             for surface in self.surfaces.values_mut() {
389                 if surface_descriptor != surface.surface_descriptor() {
390                     continue;
391                 }
392 
393                 if let Some(gpu_display_events) = self.inner.handle_next_event(surface) {
394                     for event_device in self.event_devices.values_mut() {
395                         if event_device.kind() != gpu_display_events.device_type {
396                             continue;
397                         }
398 
399                         event_device.send_report(gpu_display_events.events.iter().cloned())?;
400                     }
401                 }
402             }
403         }
404 
405         Ok(())
406     }
407 
408     /// Dispatches internal events that were received from the compositor since the last call to
409     /// `dispatch_events`.
dispatch_events(&mut self) -> GpuDisplayResult<()>410     pub fn dispatch_events(&mut self) -> GpuDisplayResult<()> {
411         let wait_events = self.wait_ctx.wait_timeout(Duration::default())?;
412 
413         if let Some(wait_event) = wait_events.iter().find(|e| e.is_hungup) {
414             base::error!(
415                 "Display signaled with a hungup event for token {:?}",
416                 wait_event.token
417             );
418             self.wait_ctx = WaitContext::new().unwrap();
419             return GpuDisplayResult::Err(GpuDisplayError::ConnectionBroken);
420         }
421 
422         for wait_event in wait_events.iter().filter(|e| e.is_writable) {
423             if let DisplayEventToken::EventDevice { event_device_id } = wait_event.token {
424                 if let Some(event_device) = self.event_devices.get_mut(&event_device_id) {
425                     if !event_device.flush_buffered_events()? {
426                         continue;
427                     }
428                     self.wait_ctx.modify(
429                         event_device,
430                         EventType::Read,
431                         DisplayEventToken::EventDevice { event_device_id },
432                     )?;
433                 }
434             }
435         }
436 
437         for wait_event in wait_events.iter().filter(|e| e.is_readable) {
438             match wait_event.token {
439                 DisplayEventToken::Display => self.dispatch_display_events()?,
440                 DisplayEventToken::EventDevice { event_device_id } => {
441                     self.handle_event_device(event_device_id)
442                 }
443             }
444         }
445 
446         Ok(())
447     }
448 
449     /// Creates a surface on the the compositor as either a top level window, or child of another
450     /// surface, returning a handle to the new surface.
create_surface( &mut self, parent_surface_id: Option<u32>, width: u32, height: u32, surf_type: SurfaceType, ) -> GpuDisplayResult<u32>451     pub fn create_surface(
452         &mut self,
453         parent_surface_id: Option<u32>,
454         width: u32,
455         height: u32,
456         surf_type: SurfaceType,
457     ) -> GpuDisplayResult<u32> {
458         if let Some(parent_id) = parent_surface_id {
459             if !self.surfaces.contains_key(&parent_id) {
460                 return Err(GpuDisplayError::InvalidSurfaceId);
461             }
462         }
463 
464         let new_surface_id = self.next_id;
465         let new_surface = self.inner.create_surface(
466             parent_surface_id,
467             new_surface_id,
468             width,
469             height,
470             surf_type,
471         )?;
472 
473         self.next_id += 1;
474         self.surfaces.insert(new_surface_id, new_surface);
475         Ok(new_surface_id)
476     }
477 
478     /// Releases a previously created surface identified by the given handle.
release_surface(&mut self, surface_id: u32)479     pub fn release_surface(&mut self, surface_id: u32) {
480         self.surfaces.remove(&surface_id);
481     }
482 
483     /// Gets a reference to an unused framebuffer for the identified surface.
framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer>484     pub fn framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer> {
485         let surface = self.surfaces.get_mut(&surface_id)?;
486         surface.framebuffer()
487     }
488 
489     /// Gets a reference to an unused framebuffer for the identified surface.
framebuffer_region( &mut self, surface_id: u32, x: u32, y: u32, width: u32, height: u32, ) -> Option<GpuDisplayFramebuffer>490     pub fn framebuffer_region(
491         &mut self,
492         surface_id: u32,
493         x: u32,
494         y: u32,
495         width: u32,
496         height: u32,
497     ) -> Option<GpuDisplayFramebuffer> {
498         let framebuffer = self.framebuffer(surface_id)?;
499         framebuffer.sub_region(x, y, width, height)
500     }
501 
502     /// Returns true if the next buffer in the buffer queue for the given surface is currently in
503     /// use.
504     ///
505     /// If the next buffer is in use, the memory returned from `framebuffer_memory` should not be
506     /// written to.
next_buffer_in_use(&self, surface_id: u32) -> bool507     pub fn next_buffer_in_use(&self, surface_id: u32) -> bool {
508         self.surfaces
509             .get(&surface_id)
510             .map(|s| s.next_buffer_in_use())
511             .unwrap_or(false)
512     }
513 
514     /// Changes the visible contents of the identified surface to the contents of the framebuffer
515     /// last returned by `framebuffer_memory` for this surface.
flip(&mut self, surface_id: u32)516     pub fn flip(&mut self, surface_id: u32) {
517         if let Some(surface) = self.surfaces.get_mut(&surface_id) {
518             surface.flip()
519         }
520     }
521 
522     /// Returns true if the identified top level surface has been told to close by the compositor,
523     /// and by extension the user.
close_requested(&self, surface_id: u32) -> bool524     pub fn close_requested(&self, surface_id: u32) -> bool {
525         self.surfaces
526             .get(&surface_id)
527             .map(|s| s.close_requested())
528             .unwrap_or(true)
529     }
530 
531     /// Imports memory to the compositor for use as a surface buffer and returns a handle
532     /// to it.
import_memory( &mut self, descriptor: &dyn AsRawDescriptor, offset: u32, stride: u32, modifiers: u64, width: u32, height: u32, fourcc: u32, ) -> GpuDisplayResult<u32>533     pub fn import_memory(
534         &mut self,
535         descriptor: &dyn AsRawDescriptor,
536         offset: u32,
537         stride: u32,
538         modifiers: u64,
539         width: u32,
540         height: u32,
541         fourcc: u32,
542     ) -> GpuDisplayResult<u32> {
543         let import_id = self.next_id;
544 
545         let gpu_display_memory = self.inner.import_memory(
546             import_id, descriptor, offset, stride, modifiers, width, height, fourcc,
547         )?;
548 
549         self.next_id += 1;
550         self.imports.insert(import_id, gpu_display_memory);
551         Ok(import_id)
552     }
553 
554     /// Releases a previously imported memory identified by the given handle.
release_import(&mut self, import_id: u32)555     pub fn release_import(&mut self, import_id: u32) {
556         self.imports.remove(&import_id);
557     }
558 
559     /// Commits any pending state for the identified surface.
commit(&mut self, surface_id: u32) -> GpuDisplayResult<()>560     pub fn commit(&mut self, surface_id: u32) -> GpuDisplayResult<()> {
561         let surface = self
562             .surfaces
563             .get_mut(&surface_id)
564             .ok_or(GpuDisplayError::InvalidSurfaceId)?;
565 
566         surface.commit()
567     }
568 
569     /// Changes the visible contents of the identified surface to that of the identified imported
570     /// buffer.
flip_to(&mut self, surface_id: u32, import_id: u32) -> GpuDisplayResult<()>571     pub fn flip_to(&mut self, surface_id: u32, import_id: u32) -> GpuDisplayResult<()> {
572         let surface = self
573             .surfaces
574             .get_mut(&surface_id)
575             .ok_or(GpuDisplayError::InvalidSurfaceId)?;
576 
577         if !self.imports.contains_key(&import_id) {
578             return Err(GpuDisplayError::InvalidImportId);
579         }
580 
581         surface.flip_to(import_id);
582         Ok(())
583     }
584 
585     /// Sets the position of the identified subsurface relative to its parent.
586     ///
587     /// The change in position will not be visible until `commit` is called for the parent surface.
set_position(&mut self, surface_id: u32, x: u32, y: u32) -> GpuDisplayResult<()>588     pub fn set_position(&mut self, surface_id: u32, x: u32, y: u32) -> GpuDisplayResult<()> {
589         let surface = self
590             .surfaces
591             .get_mut(&surface_id)
592             .ok_or(GpuDisplayError::InvalidSurfaceId)?;
593 
594         surface.set_position(x, y);
595         Ok(())
596     }
597 
598     /// Associates the scanout id with the given surface.
set_scanout_id(&mut self, surface_id: u32, scanout_id: u32) -> GpuDisplayResult<()>599     pub fn set_scanout_id(&mut self, surface_id: u32, scanout_id: u32) -> GpuDisplayResult<()> {
600         let surface = self
601             .surfaces
602             .get_mut(&surface_id)
603             .ok_or(GpuDisplayError::InvalidSurfaceId)?;
604 
605         surface.set_scanout_id(scanout_id);
606         Ok(())
607     }
608 }
609