drm: Let swap_buffers return real error

This commit is contained in:
Victor Brekenfeld 2020-04-26 20:47:52 +02:00
parent e486f7b87c
commit 378686611c
7 changed files with 48 additions and 30 deletions

View File

@ -15,7 +15,6 @@ use failure::ResultExt as FailureResultExt;
use super::Dev; use super::Dev;
use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface}; use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface};
use crate::backend::graphics::CursorBackend; use crate::backend::graphics::CursorBackend;
use crate::backend::graphics::SwapBuffersError;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct CursorState { pub struct CursorState {
@ -508,9 +507,9 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
Ok(()) Ok(())
} }
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(SwapBuffersError::AlreadySwapped); return Err(Error::DeviceInactive);
} }
let req = self let req = self
@ -521,14 +520,18 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
Some(framebuffer), Some(framebuffer),
None, None,
None, None,
) //current.mode) )?;
.map_err(|_| SwapBuffersError::ContextLost)?;
trace!(self.logger, "Queueing page flip: {:#?}", req); trace!(self.logger, "Queueing page flip: {:#?}", req);
self.atomic_commit( self.atomic_commit(
&[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock], &[AtomicCommitFlags::PageFlipEvent, AtomicCommitFlags::Nonblock],
req, req,
) )
.map_err(|_| SwapBuffersError::ContextLost)?; .compat().map_err(|source| Error::Access {
errmsg: "Page flip commit failed",
dev: self.dev_path(),
source
})?;
Ok(()) Ok(())
} }
@ -971,7 +974,7 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurface<A> {
self.0.commit(framebuffer) self.0.commit(framebuffer)
} }
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
RawSurface::page_flip(&*self.0, framebuffer) RawSurface::page_flip(&*self.0, framebuffer)
} }
} }

View File

@ -311,7 +311,7 @@ where
{ {
fallback_surface_impl!(commit_pending, &Self, bool); fallback_surface_impl!(commit_pending, &Self, bool);
fallback_surface_impl!(commit, &Self, Result<(), E>, fb: framebuffer::Handle); fallback_surface_impl!(commit, &Self, Result<(), E>, fb: framebuffer::Handle);
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), E> {
match self { match self {
FallbackSurface::Preference(dev) => RawSurface::page_flip(dev, framebuffer), FallbackSurface::Preference(dev) => RawSurface::page_flip(dev, framebuffer),
FallbackSurface::Fallback(dev) => RawSurface::page_flip(dev, framebuffer), FallbackSurface::Fallback(dev) => RawSurface::page_flip(dev, framebuffer),

View File

@ -89,6 +89,13 @@ unsafe impl<D: RawDevice + 'static> NativeSurface for GbmSurface<D> {
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> { fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
// this is safe since `eglSwapBuffers` will have been called exactly once // this is safe since `eglSwapBuffers` will have been called exactly once
// if this is used by our egl module, which is why this trait is unsafe. // if this is used by our egl module, which is why this trait is unsafe.
unsafe { self.page_flip() } match unsafe { self.page_flip() } {
Ok(()) => Ok(()),
Err(Error::FrontBuffersExhausted) => Err(SwapBuffersError::AlreadySwapped),
Err(err) => {
warn!(self.0.logger, "Page flip failed: {}", err);
Err(SwapBuffersError::Unknown(0))
}
}
} }
} }

View File

@ -39,9 +39,18 @@ pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'sta
/// Writing to GBM buffer failed /// Writing to GBM buffer failed
#[error("Writing to GBM buffer failed")] #[error("Writing to GBM buffer failed")]
BufferWriteFailed(#[source] io::Error), BufferWriteFailed(#[source] io::Error),
/// Creation of drm framebuffer failed
#[error("Creation of drm framebuffer failed")]
FramebufferCreationFailed(#[source] failure::Compat<drm::SystemError>),
/// Lock of GBM surface front buffer failed /// Lock of GBM surface front buffer failed
#[error("Lock of GBM surface font buffer failed")] #[error("Lock of GBM surface font buffer failed")]
FrontBufferLockFailed, FrontBufferLockFailed,
/// No additional buffers are available
#[error("No additional buffers are available. Did you swap twice?")]
FrontBuffersExhausted,
/// Internal state was modified
#[error("Internal state was modified. Did you change gbm userdata?")]
InvalidInternalState,
/// The GBM device was destroyed /// The GBM device was destroyed
#[error("The GBM device was destroyed")] #[error("The GBM device was destroyed")]
DeviceDestroyed, DeviceDestroyed,

View File

@ -4,12 +4,12 @@ use super::Error;
use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode}; use drm::control::{connector, crtc, framebuffer, Device as ControlDevice, Mode};
use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle}; use gbm::{self, BufferObject, BufferObjectFlags, Format as GbmFormat, SurfaceBufferHandle};
use image::{ImageBuffer, Rgba}; use image::{ImageBuffer, Rgba};
use failure::ResultExt;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use crate::backend::graphics::CursorBackend; use crate::backend::graphics::CursorBackend;
use crate::backend::graphics::SwapBuffersError;
pub(super) struct GbmSurfaceInternal<D: RawDevice + 'static> { pub(super) struct GbmSurfaceInternal<D: RawDevice + 'static> {
pub(super) dev: Rc<RefCell<gbm::Device<D>>>, pub(super) dev: Rc<RefCell<gbm::Device<D>>>,
@ -32,7 +32,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
// drop and release the old buffer // drop and release the old buffer
} }
pub unsafe fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { pub unsafe fn page_flip(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
let res = { let res = {
let nb = self.next_buffer.take(); let nb = self.next_buffer.take();
let res = nb.is_some(); let res = nb.is_some();
@ -42,7 +42,7 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
if res { if res {
// We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done // We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
warn!(self.logger, "Tried to swap with an already queued flip"); warn!(self.logger, "Tried to swap with an already queued flip");
return Err(SwapBuffersError::AlreadySwapped); return Err(Error::FrontBuffersExhausted);
} }
// supporting only one buffer would cause a lot of inconvinience and // supporting only one buffer would cause a lot of inconvinience and
@ -53,13 +53,13 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
.surface .surface
.borrow() .borrow()
.lock_front_buffer() .lock_front_buffer()
.expect("Surface only has one front buffer. Not supported by smithay"); .map_err(|_| Error::FrontBufferLockFailed)?;
// create a framebuffer if the front buffer does not have one already // create a framebuffer if the front buffer does not have one already
// (they are reused by gbm) // (they are reused by gbm)
let maybe_fb = next_bo let maybe_fb = next_bo
.userdata() .userdata()
.map_err(|_| SwapBuffersError::ContextLost)? .map_err(|_| Error::InvalidInternalState)?
.cloned(); .cloned();
let fb = if let Some(info) = maybe_fb { let fb = if let Some(info) = maybe_fb {
info info
@ -67,7 +67,8 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
let fb = self let fb = self
.crtc .crtc
.add_planar_framebuffer(&*next_bo, &[0; 4], 0) .add_planar_framebuffer(&*next_bo, &[0; 4], 0)
.map_err(|_| SwapBuffersError::ContextLost)?; .compat()
.map_err(Error::FramebufferCreationFailed)?;
next_bo.set_userdata(fb).unwrap(); next_bo.set_userdata(fb).unwrap();
fb fb
}; };
@ -75,14 +76,11 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
if self.recreated.get() { if self.recreated.get() {
debug!(self.logger, "Commiting new state"); debug!(self.logger, "Commiting new state");
if let Err(err) = self.crtc.commit(fb) { self.crtc.commit(fb).map_err(Error::Underlying)?;
error!(self.logger, "Error commiting crtc: {}", err);
return Err(SwapBuffersError::ContextLost);
}
self.recreated.set(false); self.recreated.set(false);
} else { } else {
trace!(self.logger, "Queueing Page flip"); trace!(self.logger, "Queueing Page flip");
RawSurface::page_flip(&self.crtc, fb)?; RawSurface::page_flip(&self.crtc, fb).map_err(Error::Underlying)?;
} }
self.current_frame_buffer.set(Some(fb)); self.current_frame_buffer.set(Some(fb));
@ -275,7 +273,7 @@ impl<D: RawDevice + 'static> GbmSurface<D> {
/// ///
/// When used in conjunction with an EGL context, this must be called exactly once /// When used in conjunction with an EGL context, this must be called exactly once
/// after page-flipping the associated context. /// after page-flipping the associated context.
pub unsafe fn page_flip(&self) -> ::std::result::Result<(), SwapBuffersError> { pub unsafe fn page_flip(&self) -> ::std::result::Result<(), <Self as Surface>::Error> {
self.0.page_flip() self.0.page_flip()
} }

View File

@ -12,7 +12,6 @@ use std::sync::{RwLock, atomic::Ordering};
use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface}; use crate::backend::drm::{common::Error, DevPath, RawSurface, Surface};
use crate::backend::graphics::CursorBackend; use crate::backend::graphics::CursorBackend;
use crate::backend::graphics::SwapBuffersError;
use super::Dev; use super::Dev;
@ -285,11 +284,11 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
}) })
} }
fn page_flip(&self, framebuffer: framebuffer::Handle) -> ::std::result::Result<(), SwapBuffersError> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
trace!(self.logger, "Queueing Page flip"); trace!(self.logger, "Queueing Page flip");
if !self.dev.active.load(Ordering::SeqCst) { if !self.dev.active.load(Ordering::SeqCst) {
return Err(SwapBuffersError::AlreadySwapped); return Err(Error::DeviceInactive);
} }
ControlDevice::page_flip( ControlDevice::page_flip(
@ -298,8 +297,12 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
framebuffer, framebuffer,
&[PageFlipFlags::PageFlipEvent], &[PageFlipFlags::PageFlipEvent],
None, None,
) ).compat()
.map_err(|_| SwapBuffersError::ContextLost) .map_err(|source| Error::Access {
errmsg: "Failed to page flip",
dev: self.dev_path(),
source,
})
} }
} }
@ -511,7 +514,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurface<A> {
self.0.commit(framebuffer) self.0.commit(framebuffer)
} }
fn page_flip(&self, framebuffer: framebuffer::Handle) -> ::std::result::Result<(), SwapBuffersError> { fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), Error> {
RawSurface::page_flip(&*self.0, framebuffer) RawSurface::page_flip(&*self.0, framebuffer)
} }
} }

View File

@ -51,8 +51,6 @@ use calloop::mio::Interest;
use calloop::InsertError; use calloop::InsertError;
use calloop::{LoopHandle, Source}; use calloop::{LoopHandle, Source};
use super::graphics::SwapBuffersError;
#[cfg(feature = "backend_drm_atomic")] #[cfg(feature = "backend_drm_atomic")]
pub mod atomic; pub mod atomic;
#[cfg(feature = "backend_drm")] #[cfg(feature = "backend_drm")]
@ -233,7 +231,7 @@ pub trait RawSurface: Surface + ControlDevice + BasicDevice {
/// This operation is not blocking and will produce a `vblank` event once swapping is done. /// This operation is not blocking and will produce a `vblank` event once swapping is done.
/// Make sure to [set a `DeviceHandler`](Device::set_handler) and /// Make sure to [set a `DeviceHandler`](Device::set_handler) and
/// [register the belonging `Device`](device_bind) before to receive the event in time. /// [register the belonging `Device`](device_bind) before to receive the event in time.
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>; fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
} }
/// Trait representing open devices that *may* return a `Path` /// Trait representing open devices that *may* return a `Path`