diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 6e8d830..83e64c3 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -30,6 +30,7 @@ impl Backend for Gbm { type Surface = GbmSurface; type Error = Error<<::Surface as Surface>::Error>; + // this creates an EGLDisplay for the gbm platform. unsafe fn get_display( display: ffi::NativeDisplayType, attribs: &[ffi::EGLint], diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 805c4d0..28fc5bf 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -134,6 +134,8 @@ impl DeviceHandler for InternalDeviceHan if let Some(backends) = self.backends.upgrade() { if let Some(surface) = backends.borrow().get(&crtc) { if let Some(surface) = surface.upgrade() { + // here we unlock the buffer again, that was locked during rendering, + // to make sure it is always unlocked after a successful page_flip. surface.unlock_buffer(); self.handler.vblank(crtc); } diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 2076905..7d4b1d2 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -56,7 +56,7 @@ impl GbmSurfaceInternal { .map_err(|_| Error::FrontBufferLockFailed)?; // create a framebuffer if the front buffer does not have one already - // (they are reused by gbm) + // (they are reused internally by gbm) let maybe_fb = next_bo .userdata() .map_err(|_| Error::InvalidInternalState)? @@ -80,6 +80,7 @@ impl GbmSurfaceInternal { } } + // if we re-created the surface, we need to commit the new changes, as we might trigger a modeset let result = if self.recreated.get() { debug!(self.logger, "Commiting new state"); self.crtc.commit(fb).map_err(Error::Underlying) @@ -88,6 +89,7 @@ impl GbmSurfaceInternal { RawSurface::page_flip(&self.crtc, fb).map_err(Error::Underlying) }; + // if it was successful, we can clear the re-created state match result { Ok(_) => { self.recreated.set(false); @@ -95,12 +97,15 @@ impl GbmSurfaceInternal { Ok(()) } Err(err) => { + // if there was an error we need to free the buffer again, + // otherwise we may never lock again. self.unlock_buffer(); Err(err) } } } + // this function is called, if we e.g. need to create the surface to match a new mode. pub fn recreate(&self) -> Result<(), Error<<::Surface as Surface>::Error>> { let (w, h) = self.pending_mode().size(); @@ -129,6 +134,8 @@ impl GbmSurfaceInternal { Ok(()) } + // if the underlying drm-device is closed and re-opened framebuffers may get invalided. + // here we clear them just to be sure, they get recreated on the next page_flip. pub fn clear_framebuffers(&self) { if let Some(Ok(Some(fb))) = self.next_buffer.take().map(|mut bo| bo.take_userdata()) { if let Err(err) = self.crtc.destroy_framebuffer(fb) {