diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 742f66b..372be36 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -91,7 +91,12 @@ unsafe impl NativeSurface for GbmSurface { where F: FnOnce() -> ::std::result::Result<(), SwapBuffersError>, { - if self.0.crtc.commit_pending() { + if self.0.crtc.commit_pending() || { + let fb = self.0.front_buffer.take(); + let res = fb.is_none(); + self.0.front_buffer.set(fb); + res + } { self.recreate(flip).map_err(|_| SwapBuffersError::ContextLost) } else { self.page_flip(flip) diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 208c317..a09043f 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -1,6 +1,6 @@ use super::{Device, DeviceHandler, RawDevice, ResourceHandles, ResourceInfo, Surface}; -use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; +use drm::control::{connector, crtc, Device as ControlDevice, Mode}; use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use nix::libc::dev_t; @@ -127,6 +127,9 @@ impl Device for GbmDevice { ) -> Result> { info!(self.logger, "Initializing GbmSurface"); + let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) + .chain_err(|| ErrorKind::UnderlyingBackendError)?; + let (w, h) = mode.size(); let surface = self .dev @@ -138,19 +141,6 @@ impl Device for GbmDevice { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; - // init the first screen - // (must be done before calling page_flip for the first time) - let mut front_bo = surface - .lock_front_buffer() - .chain_err(|| ErrorKind::FrontBufferLockFailed)?; - - debug!(self.logger, "FrontBuffer color format: {:?}", front_bo.format()); - - // we need a framebuffer for the front buffer - let fb = framebuffer::create(&*self.dev.borrow(), &*front_bo) - .chain_err(|| ErrorKind::UnderlyingBackendError)?; - front_bo.set_userdata(fb).unwrap(); - let cursor = Cell::new(( self.dev .borrow() @@ -166,11 +156,10 @@ impl Device for GbmDevice { let backend = Rc::new(GbmSurfaceInternal { dev: self.dev.clone(), surface: RefCell::new(surface), - crtc: Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) - .chain_err(|| ErrorKind::UnderlyingBackendError)?, + crtc: drm_surface, cursor, - current_frame_buffer: Cell::new(fb), - front_buffer: Cell::new(front_bo), + current_frame_buffer: Cell::new(None), + front_buffer: Cell::new(None), next_buffer: Cell::new(None), logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); diff --git a/src/backend/drm/gbm/session.rs b/src/backend/drm/gbm/session.rs index ffb1948..f66245d 100644 --- a/src/backend/drm/gbm/session.rs +++ b/src/backend/drm/gbm/session.rs @@ -44,11 +44,12 @@ impl { pub(super) surface: RefCell>, pub(super) crtc: ::Surface, pub(super) cursor: Cell<(BufferObject<()>, (u32, u32))>, - pub(super) current_frame_buffer: Cell, - pub(super) front_buffer: Cell>, + pub(super) current_frame_buffer: Cell>, + pub(super) front_buffer: Cell>>, pub(super) next_buffer: Cell>>, pub(super) logger: ::slog::Logger, } @@ -31,7 +31,7 @@ impl GbmSurfaceInternal { // this is called from the PageFlipHandler if let Some(next_buffer) = self.next_buffer.replace(None) { trace!(self.logger, "Releasing old front buffer"); - self.front_buffer.set(next_buffer); + self.front_buffer.set(Some(next_buffer)); // drop and release the old buffer } } @@ -83,7 +83,7 @@ impl GbmSurfaceInternal { trace!(self.logger, "Queueing Page flip"); self.crtc.page_flip(fb.handle())?; - self.current_frame_buffer.set(fb); + self.current_frame_buffer.set(Some(fb)); Ok(()) } @@ -96,7 +96,7 @@ impl GbmSurfaceInternal { // Recreate the surface and the related resources to match the new // resolution. - debug!(self.logger, "Reinitializing surface for new mode: {}:{}", w, h); + debug!(self.logger, "(Re-)Initializing surface for mode: {}:{}", w, h); let surface = self .dev .borrow_mut() @@ -107,8 +107,6 @@ impl GbmSurfaceInternal { BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, ).chain_err(|| ErrorKind::SurfaceCreationFailed)?; - flip()?; - // Clean up next_buffer { if let Some(mut old_bo) = self.next_buffer.take() { @@ -123,9 +121,11 @@ impl GbmSurfaceInternal { } } + flip()?; + // Cleanup front_buffer and init the first screen on the new front_buffer // (must be done before calling page_flip for the first time) - let mut old_front_bo = self.front_buffer.replace({ + let old_front_bo = self.front_buffer.replace({ let mut front_bo = surface .lock_front_buffer() .chain_err(|| ErrorKind::FrontBufferLockFailed)?; @@ -140,10 +140,11 @@ impl GbmSurfaceInternal { .commit(fb.handle()) .chain_err(|| ErrorKind::UnderlyingBackendError)?; + self.current_frame_buffer.set(Some(fb)); front_bo.set_userdata(fb).unwrap(); - front_bo + Some(front_bo) }); - if let Ok(Some(fb)) = old_front_bo.take_userdata() { + if let Some(Ok(Some(fb))) = old_front_bo.map(|mut bo| bo.take_userdata()) { if let Err(err) = framebuffer::destroy(&self.crtc, fb.handle()) { warn!( self.logger, @@ -283,8 +284,6 @@ impl Drop for GbmSurfaceInternal { if let Ok(Some(fb)) = { if let Some(mut next) = self.next_buffer.take() { next.take_userdata() - } else if let Ok(mut next) = self.surface.borrow().lock_front_buffer() { - next.take_userdata() } else { Ok(None) } @@ -293,7 +292,13 @@ impl Drop for GbmSurfaceInternal { let _ = framebuffer::destroy(&self.crtc, fb.handle()); } - if let Ok(Some(fb)) = self.front_buffer.get_mut().take_userdata() { + if let Ok(Some(fb)) = { + if let Some(mut next) = self.front_buffer.take() { + next.take_userdata() + } else { + Ok(None) + } + } { // ignore failure at this point let _ = framebuffer::destroy(&self.crtc, fb.handle()); }