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