drm: Documentation
This commit is contained in:
parent
0698775153
commit
f2bff6172b
|
@ -18,6 +18,7 @@ use nix::c_void;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// Backend based on a `DrmDevice` and a given crtc
|
||||||
pub struct DrmBackend(Rc<RefCell<DrmBackendInternal>>);
|
pub struct DrmBackend(Rc<RefCell<DrmBackendInternal>>);
|
||||||
|
|
||||||
impl DrmBackend {
|
impl DrmBackend {
|
||||||
|
@ -76,6 +77,9 @@ rental! {
|
||||||
}
|
}
|
||||||
use self::graphics::{Graphics, Surface};
|
use self::graphics::{Graphics, Surface};
|
||||||
|
|
||||||
|
/// Id of a `DrmBackend` related to its `DrmDevice`.
|
||||||
|
///
|
||||||
|
/// Used to track which `DrmBackend` finished page-flipping
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Id(usize);
|
pub struct Id(usize);
|
||||||
|
|
||||||
|
@ -195,6 +199,11 @@ impl DrmBackendInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrmBackend {
|
impl DrmBackend {
|
||||||
|
/// Add a connector to backend
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Errors if the new connector does not support the currently set `Mode`
|
||||||
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<(), ModeError> {
|
pub fn add_connector(&mut self, connector: connector::Handle) -> Result<(), ModeError> {
|
||||||
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)
|
||||||
|
@ -208,14 +217,23 @@ impl DrmBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a copy of the currently set connectors
|
||||||
pub fn used_connectors(&self) -> Vec<connector::Handle> {
|
pub fn used_connectors(&self) -> Vec<connector::Handle> {
|
||||||
self.0.borrow().connectors.clone()
|
self.0.borrow().connectors.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes a currently set connector
|
||||||
pub fn remove_connector(&mut self, connector: connector::Handle) {
|
pub fn remove_connector(&mut self, connector: connector::Handle) {
|
||||||
self.0.borrow_mut().connectors.retain(|x| *x != connector);
|
self.0.borrow_mut().connectors.retain(|x| *x != connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Changes the currently set mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// 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<(), DrmError> {
|
||||||
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)?
|
||||||
|
@ -278,6 +296,10 @@ impl DrmBackend {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks of the `DrmBackend` is of the given `Id`
|
||||||
|
///
|
||||||
|
/// Only produces valid results, if the `Id` is from the `DrmDevice`,
|
||||||
|
/// that created this backend.
|
||||||
pub fn is(&self, id: Id) -> bool {
|
pub fn is(&self, id: Id) -> bool {
|
||||||
self.0.borrow().own_id == id
|
self.0.borrow().own_id == id
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
use backend::graphics::egl::{CreationError, SwapBuffersError};
|
use backend::graphics::egl::{CreationError, SwapBuffersError};
|
||||||
use drm::result::Error as DrmError;
|
use drm::result::Error as DrmError;
|
||||||
use gbm::FrontBufferError;
|
use gbm::FrontBufferError;
|
||||||
|
@ -9,13 +7,21 @@ use std::error::{self, Error as ErrorTrait};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IoError;
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// The `DrmDevice` has encountered an error on an ioctl
|
||||||
Drm(DrmError),
|
Drm(DrmError),
|
||||||
|
/// The `EGLContext` could not be created
|
||||||
EGLCreation(CreationError),
|
EGLCreation(CreationError),
|
||||||
|
/// Swapping Buffers via EGL was not possible
|
||||||
EGLSwap(SwapBuffersError),
|
EGLSwap(SwapBuffersError),
|
||||||
|
/// Locking the front buffer of the underlying `GbmSurface` failed
|
||||||
Gbm(FrontBufferError),
|
Gbm(FrontBufferError),
|
||||||
|
/// A generic IO-Error happened accessing the underlying devices
|
||||||
Io(IoError),
|
Io(IoError),
|
||||||
|
/// Selected an invalid Mode
|
||||||
Mode(ModeError),
|
Mode(ModeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +104,12 @@ impl<H> From<TryNewError<Error, H>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error when trying to select an invalid mode
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ModeError {
|
pub enum ModeError {
|
||||||
|
/// `Mode` is not compatible with all given connectors
|
||||||
ModeNotSuitable,
|
ModeNotSuitable,
|
||||||
|
/// Failed to load `Mode` information
|
||||||
FailedToLoad(DrmError),
|
FailedToLoad(DrmError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,144 @@
|
||||||
|
//! Drm/Kms types and backend implementations
|
||||||
|
//!
|
||||||
|
//! This module provide a `DrmDevice` which acts as a reprensentation for any drm
|
||||||
|
//! device and can be used to create the second provided structure a `DrmBackend`.
|
||||||
|
//!
|
||||||
|
//! The latter represents a crtc of the graphics card you can render to.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! ## How to use it
|
||||||
|
//!
|
||||||
|
//! ### Initialization
|
||||||
|
//!
|
||||||
|
//! To initialize the `DrmDevice` you need either a `RawFd` or a `File` of
|
||||||
|
//! your drm node. The `File` is recommended as it represents the save api.
|
||||||
|
//!
|
||||||
|
//! Once you got your `DrmDevice` you can then use it to create `DrmBackend`s.
|
||||||
|
//! You will need to use the `drm` crate to provide the required types to create
|
||||||
|
//! a backend.
|
||||||
|
//!
|
||||||
|
//! ```rust,ignore
|
||||||
|
//! extern crate drm;
|
||||||
|
//! extern crate smithay;
|
||||||
|
//! # extern crate wayland_server;
|
||||||
|
//!
|
||||||
|
//! use drm::control::{Device as ControlDevice, ResourceInfo};
|
||||||
|
//! use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
||||||
|
//! use std::fs::OpenOptions;
|
||||||
|
//! use smithay::backend::drm::DrmDevice;
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! // Open the drm device
|
||||||
|
//! let mut options = OpenOptions::new();
|
||||||
|
//! options.read(true);
|
||||||
|
//! options.write(true);
|
||||||
|
//! let mut device = DrmDevice::new_from_file(
|
||||||
|
//! options.open("/dev/dri/card0").unwrap(), // try to detect it properly
|
||||||
|
//! None /*put a logger here*/
|
||||||
|
//! ).unwrap();
|
||||||
|
//!
|
||||||
|
//! // Get a set of all modesetting resource handles
|
||||||
|
//! let res_handles = device.resource_handles().unwrap();
|
||||||
|
//!
|
||||||
|
//! // Use first connected connector for this example
|
||||||
|
//! let connector_info = res_handles.connectors().iter()
|
||||||
|
//! .map(|conn| ConnectorInfo::load_from_device(&device, *conn).unwrap())
|
||||||
|
//! .find(|conn| conn.connection_state() == ConnectorState::Connected)
|
||||||
|
//! .unwrap();
|
||||||
|
//!
|
||||||
|
//! // Use first crtc (should be successful in most cases)
|
||||||
|
//! let crtc = res_handles.crtcs()[0];
|
||||||
|
//!
|
||||||
|
//! // Use first mode (usually the highest resolution)
|
||||||
|
//! let mode = connector_info.modes()[0];
|
||||||
|
//!
|
||||||
|
//! // Create the backend
|
||||||
|
//! let backend = device.create_backend(
|
||||||
|
//! crtc,
|
||||||
|
//! mode,
|
||||||
|
//! vec![connector_info.handle()]
|
||||||
|
//! ).unwrap();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Page Flips / Tear-free video
|
||||||
|
//! Calling the usual `EglGraphicsBackend::swap_buffers` function on a
|
||||||
|
//! `DrmBackend` works the same to finish the rendering, but will return
|
||||||
|
//! `SwapBuffersError::AlreadySwapped` for any new calls until the page flip of the
|
||||||
|
//! crtc has happened.
|
||||||
|
//!
|
||||||
|
//! You can monitor the page flips by registering the `DrmDevice` as and
|
||||||
|
//! `FdEventSourceHandler` and setting a `DrmHandler` on it. You will be notified
|
||||||
|
//! whenever a page flip has happend, so you can render the next frame immediately
|
||||||
|
//! and get a tear-free reprensentation on the display.
|
||||||
|
//!
|
||||||
|
//! You need to render at least once to successfully trigger the first event.
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! # extern crate drm;
|
||||||
|
//! # extern crate smithay;
|
||||||
|
//! # extern crate wayland_server;
|
||||||
|
//! #
|
||||||
|
//! # use drm::control::{Device as ControlDevice, ResourceInfo};
|
||||||
|
//! # use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};
|
||||||
|
//! use std::io::Error as IoError;
|
||||||
|
//! use std::os::unix::io::AsRawFd;
|
||||||
|
//! # use std::fs::OpenOptions;
|
||||||
|
//! # use std::time::Duration;
|
||||||
|
//! use smithay::backend::drm::{DrmDevice, DrmBackend, DrmHandler, Id};
|
||||||
|
//! use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
|
//! use wayland_server::sources::READ;
|
||||||
|
//! # use wayland_server::EventLoopHandle;
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! #
|
||||||
|
//! # let (_display, mut event_loop) = wayland_server::create_display();
|
||||||
|
//! #
|
||||||
|
//! # let mut options = OpenOptions::new();
|
||||||
|
//! # options.read(true);
|
||||||
|
//! # options.write(true);
|
||||||
|
//! # let mut device = DrmDevice::new_from_file(
|
||||||
|
//! # options.open("/dev/dri/card0").unwrap(), // try to detect it properly
|
||||||
|
//! # None /*put a logger here*/
|
||||||
|
//! # ).unwrap();
|
||||||
|
//! # let res_handles = device.resource_handles().unwrap();
|
||||||
|
//! # let connector_info = res_handles.connectors().iter()
|
||||||
|
//! # .map(|conn| ConnectorInfo::load_from_device(&device, *conn).unwrap())
|
||||||
|
//! # .find(|conn| conn.connection_state() == ConnectorState::Connected)
|
||||||
|
//! # .unwrap();
|
||||||
|
//! # let crtc = res_handles.crtcs()[0];
|
||||||
|
//! # let mode = connector_info.modes()[0];
|
||||||
|
//! # let backend = device.create_backend(
|
||||||
|
//! # crtc,
|
||||||
|
//! # mode,
|
||||||
|
//! # vec![connector_info.handle()]
|
||||||
|
//! # ).unwrap();
|
||||||
|
//!
|
||||||
|
//! struct MyDrmHandler(DrmBackend);
|
||||||
|
//!
|
||||||
|
//! impl DrmHandler for MyDrmHandler {
|
||||||
|
//! fn ready(&mut self, _: &mut EventLoopHandle, id: Id, _frame: u32, _duration: Duration) {
|
||||||
|
//! if self.0.is(id) { // check id in case you got multiple backends
|
||||||
|
//! // ... render surfaces ...
|
||||||
|
//! self.0.swap_buffers().unwrap(); // trigger the swap
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! fn error(&mut self, _: &mut EventLoopHandle, error: IoError) {
|
||||||
|
//! panic!("DrmDevice errored: {}", error);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // render something (like clear_color)
|
||||||
|
//! backend.swap_buffers().unwrap();
|
||||||
|
//!
|
||||||
|
//! device.set_handler(MyDrmHandler(backend));
|
||||||
|
//! let fd = device.as_raw_fd();
|
||||||
|
//! let drm_device_id = event_loop.add_handler(device);
|
||||||
|
//! let _drm_event_source = event_loop.add_fd_event_source::<DrmDevice<MyDrmHandler>>(fd, drm_device_id, READ);
|
||||||
|
//!
|
||||||
|
//! event_loop.run().unwrap();
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
use backend::graphics::egl::{EGLContext, GlAttributes, PixelFormatRequirements};
|
use backend::graphics::egl::{EGLContext, GlAttributes, PixelFormatRequirements};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
|
@ -26,6 +166,7 @@ pub use self::backend::{DrmBackend, Id};
|
||||||
use self::backend::DrmBackendInternal;
|
use self::backend::DrmBackendInternal;
|
||||||
pub use self::error::{Error as DrmError, ModeError};
|
pub use self::error::{Error as DrmError, ModeError};
|
||||||
|
|
||||||
|
/// Internal struct as required by the drm crate
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DrmDev(File);
|
pub(crate) struct DrmDev(File);
|
||||||
|
|
||||||
|
@ -72,8 +213,7 @@ rental! {
|
||||||
}
|
}
|
||||||
use self::devices::{Context, Devices};
|
use self::devices::{Context, Devices};
|
||||||
|
|
||||||
|
/// Representation of an open drm device node to create rendering backends
|
||||||
// odd naming, but makes sense for the user
|
|
||||||
pub struct DrmDevice<H: DrmHandler + 'static> {
|
pub struct DrmDevice<H: DrmHandler + 'static> {
|
||||||
context: Rc<Context>,
|
context: Rc<Context>,
|
||||||
backends: Vec<Weak<RefCell<DrmBackendInternal>>>,
|
backends: Vec<Weak<RefCell<DrmBackendInternal>>>,
|
||||||
|
@ -82,6 +222,14 @@ pub struct DrmDevice<H: DrmHandler + 'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: DrmHandler + 'static> DrmDevice<H> {
|
impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
|
/// Create a new `DrmDevice` from a raw file descriptor
|
||||||
|
///
|
||||||
|
/// Returns an error of opening the device failed or context creation was not
|
||||||
|
/// successful.
|
||||||
|
///
|
||||||
|
/// # 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, DrmError>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
@ -98,6 +246,14 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `DrmDevice` from a raw file descriptor and given `GlAttributes`
|
||||||
|
///
|
||||||
|
/// Returns an error of opening the device failed or context creation was not
|
||||||
|
/// successful.
|
||||||
|
///
|
||||||
|
/// # 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)
|
pub unsafe fn new_from_fd_with_gl_attr<L>(fd: RawFd, attributes: GlAttributes, logger: L)
|
||||||
-> Result<Self, DrmError>
|
-> Result<Self, DrmError>
|
||||||
where
|
where
|
||||||
|
@ -106,6 +262,10 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
DrmDevice::new(DrmDev::new_from_fd(fd), attributes, logger)
|
DrmDevice::new(DrmDev::new_from_fd(fd), attributes, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `DrmDevice` from a `File` of an open drm node
|
||||||
|
///
|
||||||
|
/// 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, DrmError>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>,
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
@ -122,6 +282,10 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `DrmDevice` from a `File` of an open drm node and given `GlAttributes`
|
||||||
|
///
|
||||||
|
/// 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)
|
pub fn new_from_file_with_gl_attr<L>(file: File, attributes: GlAttributes, logger: L)
|
||||||
-> Result<Self, DrmError>
|
-> Result<Self, DrmError>
|
||||||
where
|
where
|
||||||
|
@ -149,6 +313,7 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the gbm device from the drm device and create a context based on that
|
||||||
Ok(DrmDevice {
|
Ok(DrmDevice {
|
||||||
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| {
|
||||||
|
@ -174,6 +339,11 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new backend on a given crtc with a given `Mode` for a given amount
|
||||||
|
/// of `connectors` (mirroring).
|
||||||
|
///
|
||||||
|
/// 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)
|
pub fn create_backend<I>(&mut self, crtc: crtc::Handle, mode: Mode, connectors: I)
|
||||||
-> Result<DrmBackend, DrmError>
|
-> Result<DrmBackend, DrmError>
|
||||||
where
|
where
|
||||||
|
@ -183,6 +353,8 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
.new(o!("drm" => "backend", "crtc" => format!("{:?}", crtc)));
|
.new(o!("drm" => "backend", "crtc" => format!("{:?}", crtc)));
|
||||||
let own_id = self.backends.len();
|
let own_id = self.backends.len();
|
||||||
|
|
||||||
|
// TODO: Make sure we do not initialize the same crtc multiple times
|
||||||
|
// (check weak pointers and return an error otherwise)
|
||||||
let backend = Rc::new(RefCell::new(DrmBackendInternal::new(
|
let backend = Rc::new(RefCell::new(DrmBackendInternal::new(
|
||||||
self.context.clone(),
|
self.context.clone(),
|
||||||
crtc,
|
crtc,
|
||||||
|
@ -197,18 +369,20 @@ impl<H: DrmHandler + 'static> DrmDevice<H> {
|
||||||
Ok(DrmBackend::new(backend))
|
Ok(DrmBackend::new(backend))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a handler for handling finished rendering
|
||||||
pub fn set_handler(&mut self, handler: H) -> Option<H> {
|
pub fn set_handler(&mut self, handler: H) -> Option<H> {
|
||||||
let res = self.handler.take();
|
let res = self.handler.take();
|
||||||
self.handler = Some(handler);
|
self.handler = Some(handler);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the currently set handler
|
||||||
pub fn clear_handler(&mut self) -> Option<H> {
|
pub fn clear_handler(&mut self) -> Option<H> {
|
||||||
self.handler.take()
|
self.handler.take()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for users convinience
|
// for users convinience and FdEventSource registering
|
||||||
impl<H: DrmHandler + 'static> AsRawFd for DrmDevice<H> {
|
impl<H: DrmHandler + 'static> AsRawFd for DrmDevice<H> {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.context.head().head().as_raw_fd()
|
self.context.head().head().as_raw_fd()
|
||||||
|
@ -217,8 +391,20 @@ impl<H: DrmHandler + 'static> AsRawFd for DrmDevice<H> {
|
||||||
impl<H: DrmHandler + 'static> BasicDevice for DrmDevice<H> {}
|
impl<H: DrmHandler + 'static> BasicDevice for DrmDevice<H> {}
|
||||||
impl<H: DrmHandler + 'static> ControlDevice for DrmDevice<H> {}
|
impl<H: DrmHandler + 'static> ControlDevice for DrmDevice<H> {}
|
||||||
|
|
||||||
|
/// Handler for drm node events
|
||||||
|
///
|
||||||
|
/// See module-level documentation for its use
|
||||||
pub trait DrmHandler {
|
pub trait DrmHandler {
|
||||||
|
/// A `DrmBackend` has finished swapping buffers and new frame can now
|
||||||
|
/// (and should be immediately) be rendered.
|
||||||
|
///
|
||||||
|
/// The `id` argument is the `Id` of the `DrmBackend` that finished rendering,
|
||||||
|
/// check using `DrmBackend::is`.
|
||||||
fn ready(&mut self, evlh: &mut EventLoopHandle, id: Id, frame: u32, duration: Duration);
|
fn ready(&mut self, evlh: &mut EventLoopHandle, id: Id, frame: u32, duration: Duration);
|
||||||
|
/// The `DrmDevice` has thrown an error.
|
||||||
|
///
|
||||||
|
/// The related backends are most likely *not* usable anymore and
|
||||||
|
/// the whole stack has to be recreated.
|
||||||
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
|
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +431,10 @@ impl<H: DrmHandler + 'static> FdEventSourceHandler for DrmDevice<H> {
|
||||||
userdata: Box<Any>) {
|
userdata: Box<Any>) {
|
||||||
let id: Id = *userdata.downcast().unwrap();
|
let id: Id = *userdata.downcast().unwrap();
|
||||||
if let Some(backend) = self.0.backends[id.raw()].upgrade() {
|
if let Some(backend) = self.0.backends[id.raw()].upgrade() {
|
||||||
|
// we can now unlock the buffer
|
||||||
backend.borrow().unlock_buffer();
|
backend.borrow().unlock_buffer();
|
||||||
if let Some(handler) = self.0.handler.as_mut() {
|
if let Some(handler) = self.0.handler.as_mut() {
|
||||||
|
// and then call the user to render the next frame
|
||||||
handler.ready(self.1, id, frame, duration);
|
handler.ready(self.1, id, frame, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,12 @@
|
||||||
///
|
///
|
||||||
/// It therefore falls under glutin's Apache 2.0 license
|
/// It therefore falls under glutin's Apache 2.0 license
|
||||||
/// (see https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/LICENSE)
|
/// (see https://github.com/tomaka/glutin/tree/044e651edf67a2029eecc650dd42546af1501414/LICENSE)
|
||||||
|
|
||||||
use super::GraphicsBackend;
|
use super::GraphicsBackend;
|
||||||
#[cfg(feature = "backend_drm")]
|
#[cfg(feature = "backend_drm")]
|
||||||
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 slog;
|
use slog;
|
||||||
|
|
||||||
use std::error::{self, Error};
|
use std::error::{self, Error};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -22,7 +19,6 @@ use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
use wayland_client::egl as wegl;
|
use wayland_client::egl as wegl;
|
||||||
#[cfg(feature = "backend_winit")]
|
#[cfg(feature = "backend_winit")]
|
||||||
|
@ -77,10 +73,14 @@ pub enum NativeSurfacePtr {
|
||||||
Gbm(ffi::NativeWindowType),
|
Gbm(ffi::NativeWindowType),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enumerates all supported backends
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum NativeType {
|
pub enum NativeType {
|
||||||
|
/// X11 window & surface
|
||||||
X11,
|
X11,
|
||||||
|
/// Wayland surface
|
||||||
Wayland,
|
Wayland,
|
||||||
|
/// Gbm surface
|
||||||
Gbm,
|
Gbm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,9 +145,16 @@ impl error::Error for CreationError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for supported types returning valid surface pointers for initializing egl
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The returned `NativeSurfacePtr` must be valid for egl
|
||||||
|
/// and there is no way to test that.
|
||||||
pub unsafe trait NativeSurface {
|
pub unsafe trait NativeSurface {
|
||||||
|
/// Type to keep the surface valid, if needed
|
||||||
type Keep: 'static;
|
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), CreationError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +221,7 @@ pub struct EGLContext<'a, T: NativeSurface> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EGLContext<'a, ()> {
|
impl<'a> EGLContext<'a, ()> {
|
||||||
|
/// Create a new context from a given `winit`-`Window`
|
||||||
#[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)
|
||||||
|
@ -243,6 +251,7 @@ impl<'a> EGLContext<'a, ()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new context from a given `gbm::Device`
|
||||||
#[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)
|
||||||
|
@ -700,11 +709,6 @@ 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
|
||||||
///
|
|
||||||
/// # Unsafety
|
|
||||||
///
|
|
||||||
/// This method is marked unsafe, because the contents of `NativeSurface` cannot be verified and may
|
|
||||||
/// contain dangling pointers or similar unsafe content
|
|
||||||
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>, CreationError> {
|
||||||
trace!(self.logger, "Creating EGL window surface...");
|
trace!(self.logger, "Creating EGL window surface...");
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub trait GraphicsBackend {
|
||||||
/// Format representing the image drawn for the cursor.
|
/// Format representing the image drawn for the cursor.
|
||||||
type CursorFormat;
|
type CursorFormat;
|
||||||
|
|
||||||
|
/// Error the underlying backend throws if operations fail
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
/// Sets the cursor position and therefor updates the drawn cursors position.
|
/// Sets the cursor position and therefor updates the drawn cursors position.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//! Supported graphics backends:
|
//! Supported graphics backends:
|
||||||
//!
|
//!
|
||||||
//! - winit
|
//! - winit
|
||||||
|
//! - drm
|
||||||
//!
|
//!
|
||||||
//! Supported input backends:
|
//! Supported input backends:
|
||||||
//!
|
//!
|
||||||
|
|
Loading…
Reference in New Issue