• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
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 wayland.
6 
7 use std::fmt::{self, Display};
8 use std::path::Path;
9 
10 use base::{AsRawDescriptor, Error as SysError, RawDescriptor};
11 use data_model::VolatileSlice;
12 
13 mod event_device;
14 mod gpu_display_stub;
15 mod gpu_display_wl;
16 #[cfg(feature = "x")]
17 mod gpu_display_x;
18 #[cfg(feature = "x")]
19 mod keycode_converter;
20 
21 pub use event_device::{EventDevice, EventDeviceKind};
22 
23 /// An error generated by `GpuDisplay`.
24 #[derive(Debug)]
25 pub enum GpuDisplayError {
26     /// An internal allocation failed.
27     Allocate,
28     /// Connecting to the compositor failed.
29     Connect,
30     /// Creating event file descriptor failed.
31     CreateEvent,
32     /// Creating shared memory failed.
33     CreateShm(SysError),
34     /// Failed to create a surface on the compositor.
35     CreateSurface,
36     /// Failed to import a buffer to the compositor.
37     FailedImport,
38     /// The surface ID is invalid.
39     InvalidSurfaceId,
40     /// A required feature was missing.
41     RequiredFeature(&'static str),
42     /// The path is invalid.
43     InvalidPath,
44     /// The method is unsupported by the implementation.
45     Unsupported,
46 }
47 
48 impl Display for GpuDisplayError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result49     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50         use self::GpuDisplayError::*;
51 
52         match self {
53             Allocate => write!(f, "internal allocation failed"),
54             Connect => write!(f, "failed to connect to compositor"),
55             CreateEvent => write!(f, "failed to create event file descriptor"),
56             CreateShm(e) => write!(f, "failed to create shared memory: {}", e),
57             CreateSurface => write!(f, "failed to crate surface on the compositor"),
58             FailedImport => write!(f, "failed to import a buffer to the compositor"),
59             InvalidPath => write!(f, "invalid path"),
60             InvalidSurfaceId => write!(f, "invalid surface ID"),
61             RequiredFeature(feature) => write!(f, "required feature was missing: {}", feature),
62             Unsupported => write!(f, "unsupported by the implementation"),
63         }
64     }
65 }
66 
67 #[derive(Clone)]
68 pub struct GpuDisplayFramebuffer<'a> {
69     framebuffer: VolatileSlice<'a>,
70     slice: VolatileSlice<'a>,
71     stride: u32,
72     bytes_per_pixel: u32,
73 }
74 
75 impl<'a> GpuDisplayFramebuffer<'a> {
new( framebuffer: VolatileSlice<'a>, stride: u32, bytes_per_pixel: u32, ) -> GpuDisplayFramebuffer76     fn new(
77         framebuffer: VolatileSlice<'a>,
78         stride: u32,
79         bytes_per_pixel: u32,
80     ) -> GpuDisplayFramebuffer {
81         GpuDisplayFramebuffer {
82             framebuffer,
83             slice: framebuffer,
84             stride,
85             bytes_per_pixel,
86         }
87     }
88 
sub_region( &self, x: u32, y: u32, width: u32, height: u32, ) -> Option<GpuDisplayFramebuffer<'a>>89     fn sub_region(
90         &self,
91         x: u32,
92         y: u32,
93         width: u32,
94         height: u32,
95     ) -> Option<GpuDisplayFramebuffer<'a>> {
96         let x_byte_offset = x.checked_mul(self.bytes_per_pixel)?;
97         let y_byte_offset = y.checked_mul(self.stride)?;
98         let byte_offset = x_byte_offset.checked_add(y_byte_offset)?;
99 
100         let width_bytes = width.checked_mul(self.bytes_per_pixel)?;
101         let count = height
102             .checked_mul(self.stride)?
103             .checked_sub(self.stride)?
104             .checked_add(width_bytes)?;
105         let slice = self
106             .framebuffer
107             .sub_slice(byte_offset as usize, count as usize)
108             .unwrap();
109 
110         Some(GpuDisplayFramebuffer { slice, ..*self })
111     }
112 
as_volatile_slice(&self) -> VolatileSlice<'a>113     pub fn as_volatile_slice(&self) -> VolatileSlice<'a> {
114         self.slice
115     }
116 
stride(&self) -> u32117     pub fn stride(&self) -> u32 {
118         self.stride
119     }
120 }
121 
122 trait DisplayT: AsRawDescriptor {
import_dmabuf( &mut self, fd: RawDescriptor, offset: u32, stride: u32, modifiers: u64, width: u32, height: u32, fourcc: u32, ) -> Result<u32, GpuDisplayError>123     fn import_dmabuf(
124         &mut self,
125         fd: RawDescriptor,
126         offset: u32,
127         stride: u32,
128         modifiers: u64,
129         width: u32,
130         height: u32,
131         fourcc: u32,
132     ) -> Result<u32, GpuDisplayError>;
release_import(&mut self, import_id: u32)133     fn release_import(&mut self, import_id: u32);
dispatch_events(&mut self)134     fn dispatch_events(&mut self);
create_surface( &mut self, parent_surface_id: Option<u32>, width: u32, height: u32, ) -> Result<u32, GpuDisplayError>135     fn create_surface(
136         &mut self,
137         parent_surface_id: Option<u32>,
138         width: u32,
139         height: u32,
140     ) -> Result<u32, GpuDisplayError>;
release_surface(&mut self, surface_id: u32)141     fn release_surface(&mut self, surface_id: u32);
framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer>142     fn framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer>;
framebuffer_region( &mut self, surface_id: u32, x: u32, y: u32, width: u32, height: u32, ) -> Option<GpuDisplayFramebuffer>143     fn framebuffer_region(
144         &mut self,
145         surface_id: u32,
146         x: u32,
147         y: u32,
148         width: u32,
149         height: u32,
150     ) -> Option<GpuDisplayFramebuffer> {
151         let framebuffer = self.framebuffer(surface_id)?;
152         framebuffer.sub_region(x, y, width, height)
153     }
commit(&mut self, surface_id: u32)154     fn commit(&mut self, surface_id: u32);
next_buffer_in_use(&self, surface_id: u32) -> bool155     fn next_buffer_in_use(&self, surface_id: u32) -> bool;
flip(&mut self, surface_id: u32)156     fn flip(&mut self, surface_id: u32);
flip_to(&mut self, surface_id: u32, import_id: u32)157     fn flip_to(&mut self, surface_id: u32, import_id: u32);
close_requested(&self, surface_id: u32) -> bool158     fn close_requested(&self, surface_id: u32) -> bool;
set_position(&mut self, surface_id: u32, x: u32, y: u32)159     fn set_position(&mut self, surface_id: u32, x: u32, y: u32);
import_event_device(&mut self, event_device: EventDevice) -> Result<u32, GpuDisplayError>160     fn import_event_device(&mut self, event_device: EventDevice) -> Result<u32, GpuDisplayError>;
release_event_device(&mut self, event_device_id: u32)161     fn release_event_device(&mut self, event_device_id: u32);
attach_event_device(&mut self, surface_id: u32, event_device_id: u32)162     fn attach_event_device(&mut self, surface_id: u32, event_device_id: u32);
163 }
164 
165 /// A connection to the compositor and associated collection of state.
166 ///
167 /// The user of `GpuDisplay` can use `AsRawDescriptor` to poll on the compositor connection's file
168 /// descriptor. When the connection is readable, `dispatch_events` can be called to process it.
169 pub struct GpuDisplay {
170     inner: Box<dyn DisplayT>,
171     is_x: bool,
172 }
173 
174 impl GpuDisplay {
open_x<S: AsRef<str>>(display_name: Option<S>) -> Result<GpuDisplay, GpuDisplayError>175     pub fn open_x<S: AsRef<str>>(display_name: Option<S>) -> Result<GpuDisplay, GpuDisplayError> {
176         let _ = display_name;
177         #[cfg(feature = "x")]
178         {
179             let display = match display_name {
180                 Some(s) => gpu_display_x::DisplayX::open_display(Some(s.as_ref()))?,
181                 None => gpu_display_x::DisplayX::open_display(None)?,
182             };
183             let inner = Box::new(display);
184             Ok(GpuDisplay { inner, is_x: true })
185         }
186         #[cfg(not(feature = "x"))]
187         Err(GpuDisplayError::Unsupported)
188     }
189 
190     /// Opens a fresh connection to the compositor.
open_wayland<P: AsRef<Path>>( wayland_path: Option<P>, ) -> Result<GpuDisplay, GpuDisplayError>191     pub fn open_wayland<P: AsRef<Path>>(
192         wayland_path: Option<P>,
193     ) -> Result<GpuDisplay, GpuDisplayError> {
194         let display = match wayland_path {
195             Some(s) => gpu_display_wl::DisplayWl::new(Some(s.as_ref()))?,
196             None => gpu_display_wl::DisplayWl::new(None)?,
197         };
198         let inner = Box::new(display);
199         Ok(GpuDisplay { inner, is_x: false })
200     }
201 
open_stub() -> Result<GpuDisplay, GpuDisplayError>202     pub fn open_stub() -> Result<GpuDisplay, GpuDisplayError> {
203         let display = gpu_display_stub::DisplayStub::new()?;
204         let inner = Box::new(display);
205         Ok(GpuDisplay { inner, is_x: false })
206     }
207 
208     /// Return whether this display is an X display
is_x(&self) -> bool209     pub fn is_x(&self) -> bool {
210         self.is_x
211     }
212 
213     /// Imports a dmabuf to the compositor for use as a surface buffer and returns a handle to it.
import_dmabuf( &mut self, fd: RawDescriptor, offset: u32, stride: u32, modifiers: u64, width: u32, height: u32, fourcc: u32, ) -> Result<u32, GpuDisplayError>214     pub fn import_dmabuf(
215         &mut self,
216         fd: RawDescriptor,
217         offset: u32,
218         stride: u32,
219         modifiers: u64,
220         width: u32,
221         height: u32,
222         fourcc: u32,
223     ) -> Result<u32, GpuDisplayError> {
224         self.inner
225             .import_dmabuf(fd, offset, stride, modifiers, width, height, fourcc)
226     }
227 
228     /// Releases a previously imported dmabuf identified by the given handle.
release_import(&mut self, import_id: u32)229     pub fn release_import(&mut self, import_id: u32) {
230         self.inner.release_import(import_id);
231     }
232 
233     /// Dispatches internal events that were received from the compositor since the last call to
234     /// `dispatch_events`.
dispatch_events(&mut self)235     pub fn dispatch_events(&mut self) {
236         self.inner.dispatch_events()
237     }
238 
239     /// Creates a surface on the the compositor as either a top level window, or child of another
240     /// surface, returning a handle to the new surface.
create_surface( &mut self, parent_surface_id: Option<u32>, width: u32, height: u32, ) -> Result<u32, GpuDisplayError>241     pub fn create_surface(
242         &mut self,
243         parent_surface_id: Option<u32>,
244         width: u32,
245         height: u32,
246     ) -> Result<u32, GpuDisplayError> {
247         self.inner.create_surface(parent_surface_id, width, height)
248     }
249 
250     /// Releases a previously created surface identified by the given handle.
release_surface(&mut self, surface_id: u32)251     pub fn release_surface(&mut self, surface_id: u32) {
252         self.inner.release_surface(surface_id)
253     }
254 
255     /// Gets a reference to an unused framebuffer for the identified surface.
framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer>256     pub fn framebuffer(&mut self, surface_id: u32) -> Option<GpuDisplayFramebuffer> {
257         self.inner.framebuffer(surface_id)
258     }
259 
260     /// 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>261     pub fn framebuffer_region(
262         &mut self,
263         surface_id: u32,
264         x: u32,
265         y: u32,
266         width: u32,
267         height: u32,
268     ) -> Option<GpuDisplayFramebuffer> {
269         self.inner
270             .framebuffer_region(surface_id, x, y, width, height)
271     }
272 
273     /// Commits any pending state for the identified surface.
commit(&mut self, surface_id: u32)274     pub fn commit(&mut self, surface_id: u32) {
275         self.inner.commit(surface_id)
276     }
277 
278     /// Returns true if the next buffer in the buffer queue for the given surface is currently in
279     /// use.
280     ///
281     /// If the next buffer is in use, the memory returned from `framebuffer_memory` should not be
282     /// written to.
next_buffer_in_use(&self, surface_id: u32) -> bool283     pub fn next_buffer_in_use(&self, surface_id: u32) -> bool {
284         self.inner.next_buffer_in_use(surface_id)
285     }
286 
287     /// Changes the visible contents of the identified surface to the contents of the framebuffer
288     /// last returned by `framebuffer_memory` for this surface.
flip(&mut self, surface_id: u32)289     pub fn flip(&mut self, surface_id: u32) {
290         self.inner.flip(surface_id)
291     }
292 
293     /// Changes the visible contents of the identified surface to that of the identified imported
294     /// buffer.
flip_to(&mut self, surface_id: u32, import_id: u32)295     pub fn flip_to(&mut self, surface_id: u32, import_id: u32) {
296         self.inner.flip_to(surface_id, import_id)
297     }
298 
299     /// Returns true if the identified top level surface has been told to close by the compositor,
300     /// and by extension the user.
close_requested(&self, surface_id: u32) -> bool301     pub fn close_requested(&self, surface_id: u32) -> bool {
302         self.inner.close_requested(surface_id)
303     }
304 
305     /// Sets the position of the identified subsurface relative to its parent.
306     ///
307     /// 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)308     pub fn set_position(&mut self, surface_id: u32, x: u32, y: u32) {
309         self.inner.set_position(surface_id, x, y)
310     }
311 
import_event_device( &mut self, event_device: EventDevice, ) -> Result<u32, GpuDisplayError>312     pub fn import_event_device(
313         &mut self,
314         event_device: EventDevice,
315     ) -> Result<u32, GpuDisplayError> {
316         self.inner.import_event_device(event_device)
317     }
318 
release_event_device(&mut self, event_device_id: u32)319     pub fn release_event_device(&mut self, event_device_id: u32) {
320         self.inner.release_event_device(event_device_id)
321     }
322 
attach_event_device(&mut self, surface_id: u32, event_device_id: u32)323     pub fn attach_event_device(&mut self, surface_id: u32, event_device_id: u32) {
324         self.inner.attach_event_device(surface_id, event_device_id);
325     }
326 }
327 
328 impl AsRawDescriptor for GpuDisplay {
as_raw_descriptor(&self) -> RawDescriptor329     fn as_raw_descriptor(&self) -> RawDescriptor {
330         self.inner.as_raw_descriptor()
331     }
332 }
333