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