The glory of error-chain
This commit is contained in:
parent
a04bfcdd11
commit
fa6742fb5f
|
@ -22,6 +22,7 @@ clippy = { version = "*", optional = true }
|
|||
rental = "0.4.11"
|
||||
wayland-protocols = { version = "0.10.1", features = ["unstable_protocols", "server"] }
|
||||
image = "0.15.0"
|
||||
error-chain = "0.11.0"
|
||||
|
||||
[build-dependencies]
|
||||
gl_generator = "0.5"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{CrtcError, DrmError, ModeError};
|
||||
use super::devices;
|
||||
use super::error::*;
|
||||
use backend::graphics::GraphicsBackend;
|
||||
use backend::graphics::egl::{EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError};
|
||||
use drm::buffer::Buffer;
|
||||
|
@ -94,7 +94,7 @@ pub(crate) struct DrmBackendInternal {
|
|||
impl DrmBackendInternal {
|
||||
pub(crate) fn new<I, L>(context: Rc<devices::Context>, crtc: crtc::Handle, mode: Mode, connectors: I,
|
||||
own_id: usize, logger: L)
|
||||
-> Result<DrmBackendInternal, DrmError>
|
||||
-> Result<DrmBackendInternal>
|
||||
where
|
||||
I: Into<Vec<connector::Handle>>,
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
|
@ -107,11 +107,12 @@ impl DrmBackendInternal {
|
|||
|
||||
// check the connectors, if they suite the mode
|
||||
for connector in connectors.iter() {
|
||||
if !connector::Info::load_from_device(context.head().head(), *connector)?
|
||||
if !connector::Info::load_from_device(context.head().head(), *connector)
|
||||
.chain_err(|| ErrorKind::DrmDev(format!("{:?}", context.head().head())))?
|
||||
.modes()
|
||||
.contains(&mode)
|
||||
{
|
||||
return Err(DrmError::Mode(ModeError::ModeNotSuitable));
|
||||
bail!(ErrorKind::ModeNotSuitable(mode))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,23 +123,31 @@ impl DrmBackendInternal {
|
|||
Ok(GbmTypes {
|
||||
cursor: {
|
||||
// Create an unused cursor buffer (we don't want an Option here)
|
||||
context.devices.gbm.create_buffer_object(
|
||||
context
|
||||
.devices
|
||||
.gbm
|
||||
.create_buffer_object(
|
||||
1,
|
||||
1,
|
||||
GbmFormat::ARGB8888,
|
||||
&[BufferObjectFlags::Cursor, BufferObjectFlags::Write],
|
||||
)?
|
||||
)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?
|
||||
},
|
||||
surface: Surface::try_new(
|
||||
{
|
||||
debug!(log, "Creating GbmSurface");
|
||||
// create a gbm surface
|
||||
Box::new(context.devices.gbm.create_surface(
|
||||
Box::new(context
|
||||
.devices
|
||||
.gbm
|
||||
.create_surface(
|
||||
w as u32,
|
||||
h as u32,
|
||||
GbmFormat::XRGB8888,
|
||||
&[BufferObjectFlags::Scanout, BufferObjectFlags::Rendering],
|
||||
)?)
|
||||
)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?)
|
||||
},
|
||||
|surface| {
|
||||
// create an egl surface from the gbm one
|
||||
|
@ -147,15 +156,24 @@ impl DrmBackendInternal {
|
|||
|
||||
// make it active for the first `crtc::set`
|
||||
// (which is needed before the first page_flip)
|
||||
unsafe { egl_surface.make_current()? };
|
||||
egl_surface.swap_buffers()?;
|
||||
unsafe {
|
||||
egl_surface
|
||||
.make_current()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?
|
||||
};
|
||||
egl_surface
|
||||
.swap_buffers()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
||||
|
||||
// init the first screen
|
||||
// (must be done before calling page_flip for the first time)
|
||||
let mut front_bo = surface.lock_front_buffer()?;
|
||||
let mut front_bo = surface
|
||||
.lock_front_buffer()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
||||
debug!(log, "FrontBuffer color format: {:?}", front_bo.format());
|
||||
// we need a framebuffer per front buffer
|
||||
let fb = framebuffer::create(context.devices.drm, &*front_bo)?;
|
||||
let fb = framebuffer::create(context.devices.drm, &*front_bo)
|
||||
.chain_err(|| ErrorKind::DrmDev(format!("{:?}", context.devices.drm)))?;
|
||||
|
||||
debug!(log, "Initialize screen");
|
||||
crtc::set(
|
||||
|
@ -165,6 +183,8 @@ impl DrmBackendInternal {
|
|||
&connectors,
|
||||
(0, 0),
|
||||
Some(mode),
|
||||
).chain_err(
|
||||
|| ErrorKind::DrmDev(format!("{:?}", context.devices.drm)),
|
||||
)?;
|
||||
front_bo.set_userdata(fb);
|
||||
|
||||
|
@ -176,7 +196,7 @@ impl DrmBackendInternal {
|
|||
},
|
||||
})
|
||||
},
|
||||
).map_err(DrmError::from)?,
|
||||
).map_err(Error::from)?,
|
||||
})
|
||||
})?,
|
||||
crtc,
|
||||
|
@ -216,10 +236,15 @@ impl DrmBackend {
|
|||
/// # Errors
|
||||
///
|
||||
/// Errors if the new connector does not support the currently set `Mode`
|
||||
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<(), DrmError> {
|
||||
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<()> {
|
||||
let info =
|
||||
connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), connector)
|
||||
.map_err(|err| ModeError::FailedToLoad(err))?;
|
||||
.chain_err(|| {
|
||||
ErrorKind::DrmDev(format!(
|
||||
"{:?}",
|
||||
self.0.borrow().graphics.head().head().head()
|
||||
))
|
||||
})?;
|
||||
|
||||
// check if the connector can handle the current mode
|
||||
let mut internal = self.0.borrow_mut();
|
||||
|
@ -229,16 +254,21 @@ impl DrmBackend {
|
|||
.iter()
|
||||
.map(|encoder| {
|
||||
encoder::Info::load_from_device(self.0.borrow().graphics.head().head().head(), *encoder)
|
||||
.map_err(DrmError::from)
|
||||
.chain_err(|| {
|
||||
ErrorKind::DrmDev(format!(
|
||||
"{:?}",
|
||||
self.0.borrow().graphics.head().head().head()
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<encoder::Info>, DrmError>>()?;
|
||||
})
|
||||
.collect::<Result<Vec<encoder::Info>>>()?;
|
||||
|
||||
// and if any encoder supports the selected crtc
|
||||
if !encoders
|
||||
.iter()
|
||||
.any(|encoder| encoder.supports_crtc(self.0.borrow().crtc))
|
||||
{
|
||||
return Err(DrmError::Crtc(CrtcError::NoSuitableEncoder));
|
||||
bail!(ErrorKind::NoSuitableEncoder(info, self.0.borrow().crtc));
|
||||
}
|
||||
|
||||
info!(
|
||||
|
@ -249,7 +279,7 @@ impl DrmBackend {
|
|||
internal.connectors.push(connector);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DrmError::Mode(ModeError::ModeNotSuitable))
|
||||
bail!(ErrorKind::ModeNotSuitable(self.0.borrow().mode))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +300,7 @@ impl DrmBackend {
|
|||
info.connector_type()
|
||||
);
|
||||
} else {
|
||||
info!(self.0.borrow().logger, "Removeing unknown connector");
|
||||
info!(self.0.borrow().logger, "Removing unknown connector");
|
||||
}
|
||||
|
||||
self.0.borrow_mut().connectors.retain(|x| *x != connector);
|
||||
|
@ -283,14 +313,20 @@ impl DrmBackend {
|
|||
/// This will fail if not all set connectors support the new `Mode`.
|
||||
/// Several internal resources will need to be recreated to fit the new `Mode`.
|
||||
/// Other errors might occur.
|
||||
pub fn use_mode(&mut self, mode: Mode) -> Result<(), DrmError> {
|
||||
pub fn use_mode(&mut self, mode: Mode) -> Result<()> {
|
||||
// check the connectors
|
||||
for connector in self.0.borrow().connectors.iter() {
|
||||
if !connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), *connector)?
|
||||
if !connector::Info::load_from_device(self.0.borrow().graphics.head().head().head(), *connector)
|
||||
.chain_err(|| {
|
||||
ErrorKind::DrmDev(format!(
|
||||
"{:?}",
|
||||
self.0.borrow().graphics.head().head().head()
|
||||
))
|
||||
})?
|
||||
.modes()
|
||||
.contains(&mode)
|
||||
{
|
||||
return Err(DrmError::Mode(ModeError::ModeNotSuitable));
|
||||
bail!(ErrorKind::ModeNotSuitable(mode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,9 +339,7 @@ impl DrmBackend {
|
|||
|
||||
let (w, h) = mode.size();
|
||||
|
||||
internal
|
||||
.graphics
|
||||
.rent_all_mut(|graphics| -> Result<(), DrmError> {
|
||||
internal.graphics.rent_all_mut(|graphics| -> Result<()> {
|
||||
// Recreate the surface and the related resources to match the new
|
||||
// resolution.
|
||||
debug!(logger, "Reinitializing surface for new mode: {}:{}", w, h);
|
||||
|
@ -313,12 +347,17 @@ impl DrmBackend {
|
|||
{
|
||||
// create a new gbm surface
|
||||
debug!(logger, "Creating GbmSurface");
|
||||
Box::new(graphics.context.devices.gbm.create_surface(
|
||||
Box::new(graphics
|
||||
.context
|
||||
.devices
|
||||
.gbm
|
||||
.create_surface(
|
||||
w as u32,
|
||||
h as u32,
|
||||
GbmFormat::XRGB8888,
|
||||
&[BufferObjectFlags::Scanout, BufferObjectFlags::Rendering],
|
||||
)?)
|
||||
)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?)
|
||||
},
|
||||
|surface| {
|
||||
// create an egl surface from the gbm one
|
||||
|
@ -327,13 +366,23 @@ impl DrmBackend {
|
|||
|
||||
// make it active for the first `crtc::set`
|
||||
// (which is needed before the first page_flip)
|
||||
unsafe { egl_surface.make_current()? };
|
||||
egl_surface.swap_buffers()?;
|
||||
unsafe {
|
||||
egl_surface
|
||||
.make_current()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?
|
||||
};
|
||||
egl_surface
|
||||
.swap_buffers()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
||||
|
||||
let mut front_bo = surface.lock_front_buffer()?;
|
||||
let mut front_bo = surface
|
||||
.lock_front_buffer()
|
||||
.chain_err(|| ErrorKind::FailedToSwap)?;
|
||||
debug!(logger, "FrontBuffer color format: {:?}", front_bo.format());
|
||||
// we need a framebuffer per front_buffer
|
||||
let fb = framebuffer::create(graphics.context.devices.drm, &*front_bo)?;
|
||||
let fb = framebuffer::create(graphics.context.devices.drm, &*front_bo).chain_err(|| {
|
||||
ErrorKind::DrmDev(format!("{:?}", graphics.context.devices.drm))
|
||||
})?;
|
||||
|
||||
debug!(logger, "Initialize screen");
|
||||
crtc::set(
|
||||
|
@ -343,7 +392,9 @@ impl DrmBackend {
|
|||
&connectors,
|
||||
(0, 0),
|
||||
Some(mode),
|
||||
)?;
|
||||
).chain_err(|| {
|
||||
ErrorKind::DrmDev(format!("{:?}", graphics.context.devices.drm))
|
||||
})?;
|
||||
front_bo.set_userdata(fb);
|
||||
|
||||
Ok(EGL {
|
||||
|
@ -375,34 +426,46 @@ impl DrmBackend {
|
|||
|
||||
impl GraphicsBackend for DrmBackend {
|
||||
type CursorFormat = ImageBuffer<Rgba<u8>, Vec<u8>>;
|
||||
type Error = DrmError;
|
||||
type Error = Error;
|
||||
|
||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), DrmError> {
|
||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> {
|
||||
trace!(self.0.borrow().logger, "Move the cursor to {},{}", x, y);
|
||||
crtc::move_cursor(
|
||||
self.0.borrow().graphics.head().head().head(),
|
||||
self.0.borrow().crtc,
|
||||
(x as i32, y as i32),
|
||||
).map_err(DrmError::from)
|
||||
).chain_err(|| {
|
||||
ErrorKind::DrmDev(format!(
|
||||
"{:?}",
|
||||
self.0.borrow().graphics.head().head().head()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn set_cursor_representation(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32))
|
||||
-> Result<(), DrmError> {
|
||||
-> Result<()> {
|
||||
let (w, h) = buffer.dimensions();
|
||||
debug!(self.0.borrow().logger, "Importing cursor");
|
||||
/// import the cursor into a buffer we can render
|
||||
self.0
|
||||
.borrow_mut()
|
||||
.graphics
|
||||
.rent_all_mut(|graphics| -> Result<(), DrmError> {
|
||||
.rent_all_mut(|graphics| -> Result<()> {
|
||||
graphics.gbm.cursor = {
|
||||
let mut cursor = graphics.context.devices.gbm.create_buffer_object(
|
||||
let mut cursor = graphics
|
||||
.context
|
||||
.devices
|
||||
.gbm
|
||||
.create_buffer_object(
|
||||
w,
|
||||
h,
|
||||
GbmFormat::ARGB8888,
|
||||
&[BufferObjectFlags::Cursor, BufferObjectFlags::Write],
|
||||
)?;
|
||||
cursor.write(&*buffer.into_raw())?;
|
||||
)
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||
cursor
|
||||
.write(&*buffer.into_raw())
|
||||
.chain_err(|| ErrorKind::GbmInitFailed)?;
|
||||
cursor
|
||||
};
|
||||
Ok(())
|
||||
|
@ -429,7 +492,12 @@ impl GraphicsBackend for DrmBackend {
|
|||
.graphics
|
||||
.rent(|gbm| Buffer::handle(&gbm.cursor)),
|
||||
(w, h),
|
||||
).map_err(DrmError::from)
|
||||
).chain_err(|| {
|
||||
ErrorKind::DrmDev(format!(
|
||||
"{:?}",
|
||||
self.0.borrow().graphics.head().head().head()
|
||||
))
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -437,7 +505,7 @@ impl GraphicsBackend for DrmBackend {
|
|||
}
|
||||
|
||||
impl EGLGraphicsBackend for DrmBackend {
|
||||
fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
|
||||
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
self.0.borrow().graphics.rent_all(|graphics| {
|
||||
// We cannot call lock_front_buffer anymore without releasing the previous buffer, which will happen when the page flip is done
|
||||
if graphics.gbm.surface.rent(|egl| {
|
||||
|
@ -503,7 +571,7 @@ impl EGLGraphicsBackend for DrmBackend {
|
|||
.rent(|context| context.is_current())
|
||||
}
|
||||
|
||||
unsafe fn make_current(&self) -> Result<(), SwapBuffersError> {
|
||||
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
self.0
|
||||
.borrow()
|
||||
.graphics
|
||||
|
|
|
@ -1,110 +1,52 @@
|
|||
use backend::graphics::egl::{CreationError, SwapBuffersError};
|
||||
use drm::result::Error as DrmError;
|
||||
use gbm::FrontBufferError;
|
||||
//!
|
||||
//! Errors thrown by the `DrmDevice` and `DrmBackend`
|
||||
//!
|
||||
|
||||
use backend::graphics::egl;
|
||||
use drm::control::{connector, crtc, Mode};
|
||||
use rental::TryNewError;
|
||||
|
||||
use std::error::{self, Error as ErrorTrait};
|
||||
use std::fmt;
|
||||
use std::io::Error as IoError;
|
||||
|
||||
/// Error summing up error types related to all underlying libraries
|
||||
/// involved in creating the a `DrmDevice`/`DrmBackend`
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The `DrmDevice` has encountered an error on an ioctl
|
||||
Drm(DrmError),
|
||||
/// The `EGLContext` could not be created
|
||||
EGLCreation(CreationError),
|
||||
/// Swapping Buffers via EGL was not possible
|
||||
EGLSwap(SwapBuffersError),
|
||||
/// Locking the front buffer of the underlying `GbmSurface` failed
|
||||
Gbm(FrontBufferError),
|
||||
/// A generic IO-Error happened accessing the underlying devices
|
||||
Io(IoError),
|
||||
/// Selected an invalid Mode
|
||||
Mode(ModeError),
|
||||
/// Error related to the selected crtc
|
||||
Crtc(CrtcError),
|
||||
error_chain! {
|
||||
errors {
|
||||
#[doc = "The `DrmDevice` encountered an access error"]
|
||||
DrmDev(dev: String) {
|
||||
description("The drm device encountered an access error"),
|
||||
display("The drm device ({:?}) encountered an access error", dev),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DrmBackend error: {}",
|
||||
match self {
|
||||
&Error::Drm(ref x) => x as &error::Error,
|
||||
&Error::EGLCreation(ref x) => x as &error::Error,
|
||||
&Error::EGLSwap(ref x) => x as &error::Error,
|
||||
&Error::Gbm(ref x) => x as &error::Error,
|
||||
&Error::Io(ref x) => x as &error::Error,
|
||||
&Error::Mode(ref x) => x as &error::Error,
|
||||
&Error::Crtc(ref x) => x as &error::Error,
|
||||
#[doc = "Creation of gbm resource failed"]
|
||||
GbmInitFailed {
|
||||
description("Creation of gbm resource failed"),
|
||||
display("Creation of gbm resource failed"),
|
||||
}
|
||||
)
|
||||
|
||||
#[doc = "Swapping front buffers failed"]
|
||||
FailedToSwap {
|
||||
description("Swapping front buffers failed"),
|
||||
display("Swapping front buffers failed"),
|
||||
}
|
||||
|
||||
#[doc = "mode is not compatible with all given connectors"]
|
||||
ModeNotSuitable(mode: Mode) {
|
||||
description("Mode is not compatible with all given connectors"),
|
||||
display("Mode ({:?}) is not compatible with all given connectors", mode),
|
||||
}
|
||||
|
||||
#[doc = "The given crtc is already in use by another backend"]
|
||||
CrtcAlreadyInUse(crtc: crtc::Handle) {
|
||||
description("The given crtc is already in use by another backend"),
|
||||
display("The given crtc ({:?}) is already in use by another backend", crtc),
|
||||
}
|
||||
|
||||
#[doc = "No encoder was found for a given connector on the set crtc"]
|
||||
NoSuitableEncoder(connector: connector::Info, crtc: crtc::Handle) {
|
||||
description("No encoder found for given connector on set crtc"),
|
||||
display("No encoder found for the given connector '{:?}' on the set crtc ({:?})", connector.connector_type(), crtc),
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
"DrmBackend error"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match self {
|
||||
&Error::Drm(ref x) => Some(x as &error::Error),
|
||||
&Error::EGLCreation(ref x) => Some(x as &error::Error),
|
||||
&Error::EGLSwap(ref x) => Some(x as &error::Error),
|
||||
&Error::Gbm(ref x) => Some(x as &error::Error),
|
||||
&Error::Io(ref x) => Some(x as &error::Error),
|
||||
&Error::Mode(ref x) => Some(x as &error::Error),
|
||||
&Error::Crtc(ref x) => Some(x as &error::Error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DrmError> for Error {
|
||||
fn from(err: DrmError) -> Error {
|
||||
Error::Drm(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreationError> for Error {
|
||||
fn from(err: CreationError) -> Error {
|
||||
Error::EGLCreation(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SwapBuffersError> for Error {
|
||||
fn from(err: SwapBuffersError) -> Error {
|
||||
Error::EGLSwap(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FrontBufferError> for Error {
|
||||
fn from(err: FrontBufferError) -> Error {
|
||||
Error::Gbm(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
fn from(err: IoError) -> Error {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ModeError> for Error {
|
||||
fn from(err: ModeError) -> Error {
|
||||
match err {
|
||||
err @ ModeError::ModeNotSuitable => Error::Mode(err),
|
||||
ModeError::FailedToLoad(err) => Error::Drm(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CrtcError> for Error {
|
||||
fn from(err: CrtcError) -> Error {
|
||||
Error::Crtc(err)
|
||||
links {
|
||||
EGL(egl::Error, egl::ErrorKind) #[doc = "EGL error"];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,72 +55,3 @@ impl<H> From<TryNewError<Error, H>> for Error {
|
|||
err.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Error when trying to select an invalid mode
|
||||
#[derive(Debug)]
|
||||
pub enum ModeError {
|
||||
/// `Mode` is not compatible with all given connectors
|
||||
ModeNotSuitable,
|
||||
/// Failed to load `Mode` information
|
||||
FailedToLoad(DrmError),
|
||||
}
|
||||
|
||||
impl fmt::Display for ModeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description())?;
|
||||
if let Some(cause) = self.cause() {
|
||||
write!(f, "\tCause: {}", cause)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ModeError {
|
||||
fn description(&self) -> &str {
|
||||
match self {
|
||||
&ModeError::ModeNotSuitable => "Mode does not match all attached connectors",
|
||||
&ModeError::FailedToLoad(_) => "Failed to load mode information from device",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match self {
|
||||
&ModeError::FailedToLoad(ref err) => Some(err as &error::Error),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors related to the selected crtc
|
||||
#[derive(Debug)]
|
||||
pub enum CrtcError {
|
||||
/// Selected crtc is already in use by another `DrmBackend`
|
||||
AlreadyInUse,
|
||||
/// For the selected crtc no encoder exists that supports all connectors
|
||||
NoSuitableEncoder,
|
||||
}
|
||||
|
||||
impl fmt::Display for CrtcError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description())?;
|
||||
if let Some(cause) = self.cause() {
|
||||
write!(f, "\tCause: {}", cause)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CrtcError {
|
||||
fn description(&self) -> &str {
|
||||
match self {
|
||||
&CrtcError::AlreadyInUse => "Crtc is already in use by another DrmBackend",
|
||||
&CrtcError::NoSuitableEncoder => "Crtc has no supported encoder that can drive all connectors",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match self {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,11 +205,11 @@ use wayland_server::EventLoopHandle;
|
|||
use wayland_server::sources::{FdEventSourceHandler, FdInterest};
|
||||
|
||||
mod backend;
|
||||
mod error;
|
||||
pub mod error;
|
||||
|
||||
pub use self::backend::{DrmBackend, Id};
|
||||
use self::backend::DrmBackendInternal;
|
||||
pub use self::error::{CrtcError, Error as DrmError, ModeError};
|
||||
use self::error::*;
|
||||
|
||||
/// Internal struct as required by the drm crate
|
||||
#[derive(Debug)]
|
||||
|
@ -275,7 +275,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
/// # Safety
|
||||
/// The file descriptor might not be valid and needs to be owned by smithay,
|
||||
/// make sure not to share it. Otherwise undefined behavior might occur.
|
||||
pub unsafe fn new_from_fd<L>(fd: RawFd, logger: L) -> Result<Self, DrmError>
|
||||
pub unsafe fn new_from_fd<L>(fd: RawFd, logger: L) -> Result<Self>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -299,8 +299,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
/// # Safety
|
||||
/// The file descriptor might not be valid and needs to be owned by smithay,
|
||||
/// make sure not to share it. Otherwise undefined behavior might occur.
|
||||
pub unsafe fn new_from_fd_with_gl_attr<L>(fd: RawFd, attributes: GlAttributes, logger: L)
|
||||
-> Result<Self, DrmError>
|
||||
pub unsafe fn new_from_fd_with_gl_attr<L>(fd: RawFd, attributes: GlAttributes, logger: L) -> Result<Self>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -311,7 +310,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
///
|
||||
/// Returns an error if the file is no valid drm node or context creation was not
|
||||
/// successful.
|
||||
pub fn new_from_file<L>(file: File, logger: L) -> Result<Self, DrmError>
|
||||
pub fn new_from_file<L>(file: File, logger: L) -> Result<Self>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -331,15 +330,14 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
///
|
||||
/// Returns an error if the file is no valid drm node or context creation was not
|
||||
/// successful.
|
||||
pub fn new_from_file_with_gl_attr<L>(file: File, attributes: GlAttributes, logger: L)
|
||||
-> Result<Self, DrmError>
|
||||
pub fn new_from_file_with_gl_attr<L>(file: File, attributes: GlAttributes, logger: L) -> Result<Self>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
DrmDevice::new(DrmDev::new_from_file(file), attributes, logger)
|
||||
}
|
||||
|
||||
fn new<L>(drm: DrmDev, attributes: GlAttributes, logger: L) -> Result<Self, DrmError>
|
||||
fn new<L>(drm: DrmDev, attributes: GlAttributes, logger: L) -> Result<Self>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -365,7 +363,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
context: Rc::new(Context::try_new(
|
||||
Box::new(Devices::try_new(Box::new(drm), |drm| {
|
||||
debug!(log, "Creating gbm device");
|
||||
GbmDevice::new_from_drm::<DrmDevice<H>>(drm).map_err(DrmError::from)
|
||||
GbmDevice::new_from_drm::<DrmDevice<H>>(drm).chain_err(|| ErrorKind::GbmInitFailed)
|
||||
})?),
|
||||
|devices| {
|
||||
debug!(log, "Creating egl context from gbm device");
|
||||
|
@ -379,7 +377,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
..Default::default()
|
||||
},
|
||||
log.clone(),
|
||||
).map_err(DrmError::from)
|
||||
).map_err(Error::from)
|
||||
},
|
||||
)?),
|
||||
backends: Vec::new(),
|
||||
|
@ -393,15 +391,14 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
///
|
||||
/// Errors if initialization fails or the mode is not available on all given
|
||||
/// connectors.
|
||||
pub fn create_backend<I>(&mut self, crtc: crtc::Handle, mode: Mode, connectors: I)
|
||||
-> Result<DrmBackend, DrmError>
|
||||
pub fn create_backend<I>(&mut self, crtc: crtc::Handle, mode: Mode, connectors: I) -> Result<DrmBackend>
|
||||
where
|
||||
I: Into<Vec<connector::Handle>>,
|
||||
{
|
||||
for backend in self.backends.iter() {
|
||||
if let Some(backend) = backend.upgrade() {
|
||||
if backend.borrow().is_crtc(crtc) {
|
||||
return Err(DrmError::Crtc(CrtcError::AlreadyInUse));
|
||||
bail!(ErrorKind::CrtcAlreadyInUse(crtc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,21 +408,25 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
|||
|
||||
// check if we have an encoder for every connector
|
||||
for connector in connectors.iter() {
|
||||
let con_info = connector::Info::load_from_device(self.context.head().head(), *connector)?;
|
||||
let con_info = connector::Info::load_from_device(self.context.head().head(), *connector)
|
||||
.chain_err(|| {
|
||||
ErrorKind::DrmDev(format!("{:?}", self.context.head().head()))
|
||||
})?;
|
||||
|
||||
// then check for every connector which encoders it does support
|
||||
let encoders = con_info
|
||||
.encoders()
|
||||
.iter()
|
||||
.map(|encoder| {
|
||||
encoder::Info::load_from_device(self.context.head().head(), *encoder)
|
||||
.map_err(DrmError::from)
|
||||
encoder::Info::load_from_device(self.context.head().head(), *encoder).chain_err(|| {
|
||||
ErrorKind::DrmDev(format!("{:?}", self.context.head().head()))
|
||||
})
|
||||
.collect::<Result<Vec<encoder::Info>, DrmError>>()?;
|
||||
})
|
||||
.collect::<Result<Vec<encoder::Info>>>()?;
|
||||
|
||||
// and if any encoder supports the selected crtc
|
||||
if !encoders.iter().any(|encoder| encoder.supports_crtc(crtc)) {
|
||||
return Err(DrmError::Crtc(CrtcError::NoSuitableEncoder));
|
||||
bail!(ErrorKind::NoSuitableEncoder(con_info, crtc))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,11 @@ use super::GraphicsBackend;
|
|||
use gbm::{AsRaw, Device as GbmDevice, Surface as GbmSurface};
|
||||
use libloading::Library;
|
||||
use nix::{c_int, c_void};
|
||||
use rental::TryNewError;
|
||||
use slog;
|
||||
use std::error::{self, Error};
|
||||
use std::error;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
@ -74,7 +74,7 @@ pub enum NativeSurfacePtr {
|
|||
}
|
||||
|
||||
/// Enumerates all supported backends
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum NativeType {
|
||||
/// X11 window & surface
|
||||
X11,
|
||||
|
@ -82,66 +82,77 @@ pub enum NativeType {
|
|||
Wayland,
|
||||
/// Gbm surface
|
||||
Gbm,
|
||||
/// Unknown
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Error that can happen while creating an `EGLContext` or `EGLSurface`
|
||||
#[derive(Debug)]
|
||||
pub enum CreationError {
|
||||
/// I/O error from the underlying system
|
||||
IoError(io::Error),
|
||||
/// Operating System error
|
||||
OsError(String),
|
||||
/// The requested OpenGl version is not supported by the graphics system
|
||||
OpenGlVersionNotSupported,
|
||||
/// There is no pixel format available that fulfills all requirements
|
||||
NoAvailablePixelFormat,
|
||||
/// Surface creation from an unsupport combination
|
||||
///
|
||||
/// E.g creating a surface from an X11 window on a context created from a wayland display
|
||||
NonMatchingSurfaceType,
|
||||
/// Context creation is not supported on this system
|
||||
NotSupported,
|
||||
error_chain! {
|
||||
errors {
|
||||
#[doc = "The requested OpenGL version is not supported"]
|
||||
OpenGlVersionNotSupported(version: (u8, u8)) {
|
||||
description("The requested OpenGL version is not supported."),
|
||||
display("The requested OpenGL version {:?} is not supported.", version),
|
||||
}
|
||||
|
||||
impl From<io::Error> for CreationError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
CreationError::IoError(err)
|
||||
#[doc = "The EGL implementation does not support creating OpenGL ES contexts"]
|
||||
OpenGlesNotSupported {
|
||||
description("The EGL implementation does not support creating OpenGL ES contexts")
|
||||
}
|
||||
|
||||
#[doc = "No available pixel format matched the criteria"]
|
||||
NoAvailablePixelFormat {
|
||||
description("No available pixel format matched the criteria.")
|
||||
}
|
||||
|
||||
#[doc = "Surface type does not match the context type"]
|
||||
NonMatchingSurfaceType(context: NativeType, surface: NativeType) {
|
||||
description("Surface type does not match the context type."),
|
||||
display("Surface type '{:?}' does not match the context type '{:?}'.", surface, context),
|
||||
}
|
||||
|
||||
#[doc = "Context creation is not supported on the current window system"]
|
||||
NotSupported {
|
||||
description("Context creation is not supported on the current window system.")
|
||||
}
|
||||
|
||||
#[doc = "Loading libEGL failed"]
|
||||
LoadingEGLFailed {
|
||||
description("Loading libEGL failed"),
|
||||
}
|
||||
|
||||
#[doc = "EGL was unable to optain a valid EGL Display"]
|
||||
DisplayNotSupported {
|
||||
description("EGL was unable to optain a valid EGL Display")
|
||||
}
|
||||
|
||||
#[doc = "eglInitialize returned an error"]
|
||||
InitFailed {
|
||||
description("Failed to initialize EGL")
|
||||
}
|
||||
|
||||
#[doc = "Failed to configure the EGL context"]
|
||||
ConfigFailed {
|
||||
description("Failed to configure the EGL context")
|
||||
}
|
||||
|
||||
#[doc = "Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements"]
|
||||
CreationFailed {
|
||||
description("Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements")
|
||||
}
|
||||
|
||||
#[doc = "eglCreateWindowSurface failed"]
|
||||
SurfaceCreationFailed {
|
||||
description("Failed to create a new EGLSurface")
|
||||
}
|
||||
|
||||
#[doc = "The reason of failure could not be determined"]
|
||||
Unknown(err_no: u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
formatter.write_str(self.description())?;
|
||||
if let Some(err) = error::Error::cause(self) {
|
||||
write!(formatter, ": {}", err)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CreationError::IoError(ref err) => err.description(),
|
||||
CreationError::OsError(ref text) => text,
|
||||
CreationError::OpenGlVersionNotSupported => {
|
||||
"The requested OpenGL version is not \
|
||||
supported."
|
||||
}
|
||||
CreationError::NoAvailablePixelFormat => {
|
||||
"Couldn't find any pixel format that matches \
|
||||
the criterias."
|
||||
}
|
||||
CreationError::NonMatchingSurfaceType => "Surface type does not match the context type.",
|
||||
CreationError::NotSupported => "Context creation is not supported on the current window system",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
CreationError::IoError(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
impl<H> From<TryNewError<Error, H>> for Error {
|
||||
fn from(err: TryNewError<Error, H>) -> Error {
|
||||
err.0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,20 +166,22 @@ pub unsafe trait NativeSurface {
|
|||
type Keep: 'static;
|
||||
|
||||
/// Return a surface for the given type if possible
|
||||
fn surface(&self, backend: NativeType) -> Result<(NativeSurfacePtr, Self::Keep), CreationError>;
|
||||
fn surface(&self, backend: NativeType) -> Result<(NativeSurfacePtr, Self::Keep)>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "backend_winit")]
|
||||
unsafe impl NativeSurface for WinitWindow {
|
||||
type Keep = Option<wegl::WlEglSurface>;
|
||||
|
||||
fn surface(&self, backend_type: NativeType)
|
||||
-> Result<(NativeSurfacePtr, Option<wegl::WlEglSurface>), CreationError> {
|
||||
fn surface(&self, backend_type: NativeType) -> Result<(NativeSurfacePtr, Option<wegl::WlEglSurface>)> {
|
||||
match backend_type {
|
||||
NativeType::X11 => if let Some(window) = self.get_xlib_window() {
|
||||
Ok((NativeSurfacePtr::X11(window), None))
|
||||
} else {
|
||||
return Err(CreationError::NonMatchingSurfaceType);
|
||||
bail!(ErrorKind::NonMatchingSurfaceType(
|
||||
NativeType::Wayland,
|
||||
NativeType::X11
|
||||
));
|
||||
},
|
||||
NativeType::Wayland => if let Some(surface) = self.get_wayland_surface() {
|
||||
let (w, h) = self.get_inner_size().unwrap();
|
||||
|
@ -179,9 +192,12 @@ unsafe impl NativeSurface for WinitWindow {
|
|||
Some(egl_surface),
|
||||
))
|
||||
} else {
|
||||
return Err(CreationError::NonMatchingSurfaceType);
|
||||
bail!(ErrorKind::NonMatchingSurfaceType(
|
||||
NativeType::X11,
|
||||
NativeType::Wayland
|
||||
));
|
||||
},
|
||||
_ => Err(CreationError::NonMatchingSurfaceType),
|
||||
x => bail!(ErrorKind::NonMatchingSurfaceType(NativeType::Unknown, x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,18 +206,18 @@ unsafe impl NativeSurface for WinitWindow {
|
|||
unsafe impl<'a, T: 'static> NativeSurface for GbmSurface<'a, T> {
|
||||
type Keep = ();
|
||||
|
||||
fn surface(&self, backend: NativeType) -> Result<(NativeSurfacePtr, Self::Keep), CreationError> {
|
||||
fn surface(&self, backend: NativeType) -> Result<(NativeSurfacePtr, Self::Keep)> {
|
||||
match backend {
|
||||
NativeType::Gbm => Ok((NativeSurfacePtr::Gbm(self.as_raw() as *const _), ())),
|
||||
_ => Err(CreationError::NonMatchingSurfaceType),
|
||||
x => bail!(ErrorKind::NonMatchingSurfaceType(NativeType::Gbm, x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl NativeSurface for () {
|
||||
type Keep = ();
|
||||
fn surface(&self, _backend: NativeType) -> Result<(NativeSurfacePtr, ()), CreationError> {
|
||||
Err(CreationError::NotSupported)
|
||||
fn surface(&self, _backend: NativeType) -> Result<(NativeSurfacePtr, ())> {
|
||||
bail!(ErrorKind::NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +241,7 @@ impl<'a> EGLContext<'a, ()> {
|
|||
#[cfg(feature = "backend_winit")]
|
||||
pub fn new_from_winit<L>(window: &'a WinitWindow, attributes: GlAttributes,
|
||||
reqs: PixelFormatRequirements, logger: L)
|
||||
-> Result<EGLContext<'a, WinitWindow>, CreationError>
|
||||
-> Result<EGLContext<'a, WinitWindow>>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -242,7 +258,7 @@ impl<'a> EGLContext<'a, ()> {
|
|||
NativeDisplayPtr::Wayland(display)
|
||||
} else {
|
||||
error!(log, "Window is backed by an unsupported graphics framework");
|
||||
return Err(CreationError::NotSupported);
|
||||
bail!(ErrorKind::NotSupported)
|
||||
},
|
||||
attributes,
|
||||
reqs,
|
||||
|
@ -255,7 +271,7 @@ impl<'a> EGLContext<'a, ()> {
|
|||
#[cfg(feature = "backend_drm")]
|
||||
pub fn new_from_gbm<L, U: 'static>(gbm: &'a GbmDevice<'a>, attributes: GlAttributes,
|
||||
reqs: PixelFormatRequirements, logger: L)
|
||||
-> Result<EGLContext<'a, GbmSurface<'a, U>>, CreationError>
|
||||
-> Result<EGLContext<'a, GbmSurface<'a, U>>>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -275,7 +291,7 @@ impl<'a> EGLContext<'a, ()> {
|
|||
impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
||||
unsafe fn new(native: NativeDisplayPtr, mut attributes: GlAttributes, reqs: PixelFormatRequirements,
|
||||
log: ::slog::Logger)
|
||||
-> Result<EGLContext<'a, T>, CreationError>
|
||||
-> Result<EGLContext<'a, T>>
|
||||
where
|
||||
T: NativeSurface,
|
||||
{
|
||||
|
@ -297,12 +313,12 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Some((1, _)) => {
|
||||
Some((1, x)) => {
|
||||
error!(
|
||||
log,
|
||||
"OpenGLES 1.* is not supported by the EGL renderer backend"
|
||||
);
|
||||
return Err(CreationError::OpenGlVersionNotSupported);
|
||||
bail!(ErrorKind::OpenGlVersionNotSupported((1, x)));
|
||||
}
|
||||
Some(version) => {
|
||||
error!(
|
||||
|
@ -310,12 +326,12 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
"OpenGLES {:?} is unknown and not supported by the EGL renderer backend",
|
||||
version
|
||||
);
|
||||
return Err(CreationError::OpenGlVersionNotSupported);
|
||||
bail!(ErrorKind::OpenGlVersionNotSupported(version));
|
||||
}
|
||||
};
|
||||
|
||||
trace!(log, "Loading libEGL");
|
||||
let lib = Library::new("libEGL.so.1")?;
|
||||
let lib = Library::new("libEGL.so.1").chain_err(|| ErrorKind::LoadingEGLFailed)?;
|
||||
let egl = ffi::egl::Egl::load_with(|sym| {
|
||||
let name = CString::new(sym).unwrap();
|
||||
let symbol = lib.get::<*mut c_void>(name.as_bytes());
|
||||
|
@ -418,6 +434,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
|
||||
if display == ffi::egl::NO_DISPLAY {
|
||||
error!(log, "EGL Display is not valid");
|
||||
bail!(ErrorKind::DisplayNotSupported);
|
||||
}
|
||||
|
||||
let egl_version = {
|
||||
|
@ -425,7 +442,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
let mut minor: ffi::egl::types::EGLint = mem::uninitialized();
|
||||
|
||||
if egl.Initialize(display, &mut major, &mut minor) == 0 {
|
||||
return Err(CreationError::OsError(String::from("eglInitialize failed")));
|
||||
bail!(ErrorKind::InitFailed);
|
||||
}
|
||||
|
||||
info!(log, "EGL Initialized");
|
||||
|
@ -451,7 +468,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
log,
|
||||
"OpenGLES not supported by the underlying EGL implementation"
|
||||
);
|
||||
return Err(CreationError::OpenGlVersionNotSupported);
|
||||
bail!(ErrorKind::OpenGlesNotSupported);
|
||||
}
|
||||
|
||||
let descriptor = {
|
||||
|
@ -477,7 +494,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
log,
|
||||
"OpenglES 3.* is not supported on EGL Versions lower then 1.3"
|
||||
);
|
||||
return Err(CreationError::NoAvailablePixelFormat);
|
||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
||||
}
|
||||
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES3");
|
||||
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||
|
@ -492,7 +509,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
log,
|
||||
"OpenglES 2.* is not supported on EGL Versions lower then 1.3"
|
||||
);
|
||||
return Err(CreationError::NoAvailablePixelFormat);
|
||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
||||
}
|
||||
trace!(log, "Setting RENDERABLE_TYPE to OPENGL_ES2");
|
||||
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||
|
@ -561,7 +578,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
|
||||
if reqs.stereoscopy {
|
||||
error!(log, "Stereoscopy is currently unsupported (sorry!)");
|
||||
return Err(CreationError::NoAvailablePixelFormat);
|
||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
||||
}
|
||||
|
||||
out.push(ffi::egl::NONE as c_int);
|
||||
|
@ -579,13 +596,11 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
&mut num_configs,
|
||||
) == 0
|
||||
{
|
||||
return Err(CreationError::OsError(
|
||||
String::from("eglChooseConfig failed"),
|
||||
));
|
||||
bail!(ErrorKind::ConfigFailed);
|
||||
}
|
||||
if num_configs == 0 {
|
||||
error!(log, "No matching color format found");
|
||||
return Err(CreationError::NoAvailablePixelFormat);
|
||||
bail!(ErrorKind::NoAvailablePixelFormat);
|
||||
}
|
||||
|
||||
// analyzing each config
|
||||
|
@ -596,7 +611,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
let res = $egl.GetConfigAttrib($display, $config,
|
||||
$attr as ffi::egl::types::EGLint, &mut value);
|
||||
if res == 0 {
|
||||
return Err(CreationError::OsError(String::from("eglGetConfigAttrib failed")));
|
||||
bail!(ErrorKind::ConfigFailed);
|
||||
}
|
||||
value
|
||||
}
|
||||
|
@ -654,14 +669,8 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
|
||||
if context.is_null() {
|
||||
match egl.GetError() as u32 {
|
||||
ffi::egl::BAD_ATTRIBUTE => {
|
||||
error!(
|
||||
log,
|
||||
"Context creation failed as one or more requirements could not be met. Try removing some gl attributes or pixel format requirements"
|
||||
);
|
||||
return Err(CreationError::OpenGlVersionNotSupported);
|
||||
}
|
||||
e => panic!("eglCreateContext failed: 0x{:x}", e),
|
||||
ffi::egl::BAD_ATTRIBUTE => bail!(ErrorKind::CreationFailed),
|
||||
err_no => bail!(ErrorKind::Unknown(err_no)),
|
||||
}
|
||||
}
|
||||
debug!(log, "EGL context successfully created");
|
||||
|
@ -709,7 +718,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
}
|
||||
|
||||
/// Creates a surface bound to the given egl context for rendering
|
||||
pub fn create_surface<'b>(&'a self, native: &'b T) -> Result<EGLSurface<'a, 'b, T>, CreationError> {
|
||||
pub fn create_surface<'b>(&'a self, native: &'b T) -> Result<EGLSurface<'a, 'b, T>> {
|
||||
trace!(self.logger, "Creating EGL window surface...");
|
||||
|
||||
let (surface, keep) = native.surface(self.backend_type)?;
|
||||
|
@ -728,9 +737,7 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
};
|
||||
|
||||
if egl_surface.is_null() {
|
||||
return Err(CreationError::OsError(
|
||||
String::from("eglCreateWindowSurface failed"),
|
||||
));
|
||||
bail!(ErrorKind::SurfaceCreationFailed);
|
||||
}
|
||||
|
||||
debug!(self.logger, "EGL surface successfully created");
|
||||
|
@ -801,7 +808,7 @@ impl<'a, 'b, T: NativeSurface> DerefMut for EGLSurface<'a, 'b, T> {
|
|||
|
||||
impl<'context, 'surface, T: NativeSurface> EGLSurface<'context, 'surface, T> {
|
||||
/// Swaps buffers at the end of a frame.
|
||||
pub fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
|
||||
pub fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
let ret = unsafe {
|
||||
self.context
|
||||
.egl
|
||||
|
@ -824,7 +831,7 @@ impl<'context, 'surface, T: NativeSurface> EGLSurface<'context, 'surface, T> {
|
|||
///
|
||||
/// This function is marked unsafe, because the context cannot be made current
|
||||
/// on multiple threads.
|
||||
pub unsafe fn make_current(&self) -> Result<(), SwapBuffersError> {
|
||||
pub unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
let ret = self.context.egl.MakeCurrent(
|
||||
self.context.display as *const _,
|
||||
self.surface as *const _,
|
||||
|
@ -879,7 +886,8 @@ pub enum SwapBuffersError {
|
|||
}
|
||||
|
||||
impl fmt::Display for SwapBuffersError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
|
||||
use std::error::Error;
|
||||
write!(formatter, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
@ -983,7 +991,7 @@ pub struct PixelFormat {
|
|||
/// and can be used to render upon
|
||||
pub trait EGLGraphicsBackend: GraphicsBackend {
|
||||
/// Swaps buffers at the end of a frame.
|
||||
fn swap_buffers(&self) -> Result<(), SwapBuffersError>;
|
||||
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError>;
|
||||
|
||||
/// Returns the address of an OpenGL function.
|
||||
///
|
||||
|
@ -1006,7 +1014,7 @@ pub trait EGLGraphicsBackend: GraphicsBackend {
|
|||
///
|
||||
/// This function is marked unsafe, because the context cannot be made current
|
||||
/// on multiple threads.
|
||||
unsafe fn make_current(&self) -> Result<(), SwapBuffersError>;
|
||||
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError>;
|
||||
|
||||
/// Returns the pixel format of the main framebuffer of the context.
|
||||
fn get_pixel_format(&self) -> PixelFormat;
|
||||
|
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
use backend::{SeatInternal, TouchSlotInternal};
|
||||
use backend::graphics::GraphicsBackend;
|
||||
use backend::graphics::egl::{CreationError, EGLContext, EGLGraphicsBackend, GlAttributes, PixelFormat,
|
||||
use backend::graphics::egl::{self, EGLContext, EGLGraphicsBackend, GlAttributes, PixelFormat,
|
||||
PixelFormatRequirements, SwapBuffersError};
|
||||
use backend::input::{Axis, AxisSource, Event as BackendEvent, InputBackend, InputHandler, KeyState,
|
||||
KeyboardKeyEvent, MouseButton, MouseButtonState, PointerAxisEvent, PointerButtonEvent,
|
||||
PointerMotionAbsoluteEvent, Seat, SeatCapabilities, TouchCancelEvent, TouchDownEvent,
|
||||
TouchMotionEvent, TouchSlot, TouchUpEvent, UnusedEvent};
|
||||
use nix::c_void;
|
||||
|
||||
use rental::TryNewError;
|
||||
use std::cmp;
|
||||
use std::error::Error;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use winit::{CreationError as WinitCreationError, ElementState, Event, EventsLoop, KeyboardInput,
|
||||
MouseButton as WinitMouseButton, MouseCursor, MouseScrollDelta, Touch, TouchPhase,
|
||||
WindowBuilder, WindowEvent};
|
||||
use winit::{ElementState, Event, EventsLoop, KeyboardInput, MouseButton as WinitMouseButton, MouseCursor,
|
||||
MouseScrollDelta, Touch, TouchPhase, WindowBuilder, WindowEvent};
|
||||
|
||||
rental! {
|
||||
mod rental {
|
||||
|
@ -40,6 +39,24 @@ rental! {
|
|||
|
||||
use self::rental::{Window, EGL};
|
||||
|
||||
error_chain! {
|
||||
errors {
|
||||
#[doc = "Failed to initialize a window"]
|
||||
InitFailed {
|
||||
description("Failed to initialize a window")
|
||||
}
|
||||
}
|
||||
|
||||
links {
|
||||
EGL(egl::Error, egl::ErrorKind) #[doc = "EGL error"];
|
||||
}
|
||||
}
|
||||
|
||||
impl<H> From<TryNewError<Error, H>> for Error {
|
||||
fn from(err: TryNewError<Error, H>) -> Error {
|
||||
err.0
|
||||
}
|
||||
}
|
||||
/// Window with an active EGL Context created by `winit`. Implements the
|
||||
/// `EGLGraphicsBackend` graphics backend trait
|
||||
pub struct WinitGraphicsBackend {
|
||||
|
@ -64,7 +81,7 @@ pub struct WinitInputBackend {
|
|||
/// Create a new `WinitGraphicsBackend`, which implements the `EGLGraphicsBackend`
|
||||
/// graphics backend trait and a corresponding `WinitInputBackend`, which implements
|
||||
/// the `InputBackend` trait
|
||||
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend), CreationError>
|
||||
pub fn init<L>(logger: L) -> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -81,7 +98,7 @@ where
|
|||
/// graphics backend trait, from a given `WindowBuilder` struct and a corresponding
|
||||
/// `WinitInputBackend`, which implements the `InputBackend` trait
|
||||
pub fn init_from_builder<L>(builder: WindowBuilder, logger: L)
|
||||
-> Result<(WinitGraphicsBackend, WinitInputBackend), CreationError>
|
||||
-> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -101,9 +118,8 @@ where
|
|||
/// graphics backend trait, from a given `WindowBuilder` struct, as well as given
|
||||
/// `GlAttributes` for further customization of the rendering pipeline and a
|
||||
/// corresponding `WinitInputBackend`, which implements the `InputBackend` trait.
|
||||
pub fn init_from_builder_with_gl_attr<L>(
|
||||
builder: WindowBuilder, attributes: GlAttributes, logger: L)
|
||||
-> Result<(WinitGraphicsBackend, WinitInputBackend), CreationError>
|
||||
pub fn init_from_builder_with_gl_attr<L>(builder: WindowBuilder, attributes: GlAttributes, logger: L)
|
||||
-> Result<(WinitGraphicsBackend, WinitInputBackend)>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
{
|
||||
|
@ -111,11 +127,13 @@ where
|
|||
info!(log, "Initializing a winit backend");
|
||||
|
||||
let events_loop = EventsLoop::new();
|
||||
let winit_window = builder.build(&events_loop)?;
|
||||
let winit_window = builder
|
||||
.build(&events_loop)
|
||||
.chain_err(|| ErrorKind::InitFailed)?;
|
||||
debug!(log, "Window created");
|
||||
|
||||
let window = match Window::try_new(Box::new(winit_window), |window| {
|
||||
match EGL::try_new(
|
||||
let window = Rc::new(Window::try_new(Box::new(winit_window), |window| {
|
||||
EGL::try_new(
|
||||
Box::new(match EGLContext::new_from_winit(
|
||||
&*window,
|
||||
attributes,
|
||||
|
@ -128,20 +146,12 @@ where
|
|||
log.clone(),
|
||||
) {
|
||||
Ok(context) => context,
|
||||
Err(err) => {
|
||||
error!(log, "EGLContext creation failed:\n {}", err);
|
||||
return Err(err);
|
||||
}
|
||||
Err(err) => bail!(err),
|
||||
}),
|
||||
|context| context.create_surface(window),
|
||||
) {
|
||||
Ok(x) => Ok(x),
|
||||
Err(::rental::TryNewError(err, _)) => return Err(err),
|
||||
}
|
||||
}) {
|
||||
Ok(x) => Rc::new(x),
|
||||
Err(::rental::TryNewError(err, _)) => return Err(err),
|
||||
};
|
||||
).map_err(egl::Error::from)
|
||||
.map_err(Error::from)
|
||||
})?);
|
||||
|
||||
Ok((
|
||||
WinitGraphicsBackend {
|
||||
|
@ -172,12 +182,13 @@ impl GraphicsBackend for WinitGraphicsBackend {
|
|||
type CursorFormat = MouseCursor;
|
||||
type Error = ();
|
||||
|
||||
fn set_cursor_position(&self, x: u32, y: u32) -> Result<(), ()> {
|
||||
fn set_cursor_position(&self, x: u32, y: u32) -> ::std::result::Result<(), ()> {
|
||||
debug!(self.logger, "Setting cursor position to {:?}", (x, y));
|
||||
self.window.head().set_cursor_position(x as i32, y as i32)
|
||||
}
|
||||
|
||||
fn set_cursor_representation(&self, cursor: Self::CursorFormat, _hotspot: (u32, u32)) -> Result<(), ()> {
|
||||
fn set_cursor_representation(&self, cursor: Self::CursorFormat, _hotspot: (u32, u32))
|
||||
-> ::std::result::Result<(), ()> {
|
||||
// Cannot log this one, as `CursorFormat` is not `Debug` and should not be
|
||||
debug!(self.logger, "Changing cursor representation");
|
||||
self.window.head().set_cursor(cursor);
|
||||
|
@ -186,7 +197,7 @@ impl GraphicsBackend for WinitGraphicsBackend {
|
|||
}
|
||||
|
||||
impl EGLGraphicsBackend for WinitGraphicsBackend {
|
||||
fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
|
||||
fn swap_buffers(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
trace!(self.logger, "Swapping buffers");
|
||||
self.window
|
||||
.rent(|egl| egl.rent(|surface| surface.swap_buffers()))
|
||||
|
@ -208,7 +219,7 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
|
|||
self.window.rent(|egl| egl.head().is_current())
|
||||
}
|
||||
|
||||
unsafe fn make_current(&self) -> Result<(), SwapBuffersError> {
|
||||
unsafe fn make_current(&self) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
debug!(self.logger, "Setting EGL context to be the current context");
|
||||
self.window
|
||||
.rent(|egl| egl.rent(|surface| surface.make_current()))
|
||||
|
@ -228,7 +239,7 @@ pub enum WinitInputError {
|
|||
WindowClosed,
|
||||
}
|
||||
|
||||
impl Error for WinitInputError {
|
||||
impl error::Error for WinitInputError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
WinitInputError::WindowClosed => "Glutin Window was closed",
|
||||
|
@ -238,6 +249,7 @@ impl Error for WinitInputError {
|
|||
|
||||
impl fmt::Display for WinitInputError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use std::error::Error;
|
||||
write!(f, "{}", self.description())
|
||||
}
|
||||
}
|
||||
|
@ -576,7 +588,7 @@ impl InputBackend for WinitInputBackend {
|
|||
///
|
||||
/// The linked `WinitGraphicsBackend` will error with a lost Context and should
|
||||
/// not be used anymore as well.
|
||||
fn dispatch_new_events(&mut self) -> Result<(), WinitInputError> {
|
||||
fn dispatch_new_events(&mut self) -> ::std::result::Result<(), WinitInputError> {
|
||||
let mut closed = false;
|
||||
|
||||
{
|
||||
|
@ -831,12 +843,3 @@ impl From<ElementState> for MouseButtonState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WinitCreationError> for CreationError {
|
||||
fn from(error: WinitCreationError) -> Self {
|
||||
match error {
|
||||
WinitCreationError::OsError(x) => CreationError::OsError(x),
|
||||
WinitCreationError::NotSupported => CreationError::NotSupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#![cfg_attr(feature = "clippy", feature(plugin))]
|
||||
#![cfg_attr(feature = "clippy", plugin(clippy))]
|
||||
// `error_chain!` can recurse deeply
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate image;
|
||||
extern crate nix;
|
||||
|
@ -36,6 +38,9 @@ extern crate glium;
|
|||
extern crate slog;
|
||||
extern crate slog_stdlog;
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
pub mod backend;
|
||||
pub mod compositor;
|
||||
pub mod shm;
|
||||
|
|
Loading…
Reference in New Issue