docs: added drm

This commit is contained in:
Victor Brekenfeld 2018-12-02 20:07:50 +01:00
parent b160a91f8a
commit 174c150887
1 changed files with 140 additions and 2 deletions

View File

@ -1,3 +1,40 @@
//!
//!
//! This module provides Traits reprensentating open devices
//! and their surfaces to render contents.
//!
//! ---
//!
//! Initialization of devices happens through an open file descriptor
//! of a drm device.
//!
//! ---
//!
//! Initialization of surfaces happens through the types provided by
//! [`drm-rs`](https://docs.rs/drm/0.3.4/drm/).
//!
//! Four entities are relevant for the initialization procedure.
//!
//! [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)s represent scanout engines
//! of the device pointer to one framebuffer.
//! Their responsibility is to read the data of the framebuffer and export it into an "Encoder".
//! The number of crtc's represent the number of independant output devices the hardware may handle.
//!
//! An [`encoder`](https://docs.rs/drm/0.3.4/drm/control/encoder/index.html) encodes the data of
//! connected crtcs into a video signal for a fixed set of connectors.
//! E.g. you might have an analog encoder based on a DAG for VGA ports, but another one for digital ones.
//! Also not every encoder might be connected to every crtc.
//!
//! A [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html) represents a port
//! on your computer, possibly with a connected monitor, TV, capture card, etc.
//!
//! On surface creation a matching encoder for your `encoder`-`connector` is automatically selected,
//! if it exists, which means you still need to check your configuration.
//!
//! At last a [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html) needs to be selected,
//! supported by the `crtc` in question.
//!
pub use drm::{ pub use drm::{
control::{connector, crtc, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo}, control::{connector, crtc, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo},
Device as BasicDevice, Device as BasicDevice,
@ -23,55 +60,155 @@ pub mod gbm;
#[cfg(feature = "backend_drm_legacy")] #[cfg(feature = "backend_drm_legacy")]
pub mod legacy; pub mod legacy;
/// Trait to receive events of a bound [`Device`](trait.Device.html)
///
/// See [`device_bind`](fn.device_bind.html)
pub trait DeviceHandler { pub trait DeviceHandler {
/// The [`Device`](trait.Device.html) type this handler can handle
type Device: Device + ?Sized; type Device: Device + ?Sized;
/// A vblank blank event on the provided crtc has happend
fn vblank(&mut self, crtc: crtc::Handle); fn vblank(&mut self, crtc: crtc::Handle);
/// An error happend while processing events
fn error(&mut self, error: <<<Self as DeviceHandler>::Device as Device>::Surface as Surface>::Error); fn error(&mut self, error: <<<Self as DeviceHandler>::Device as Device>::Surface as Surface>::Error);
} }
/// An open drm device
pub trait Device: AsRawFd + DevPath { pub trait Device: AsRawFd + DevPath {
/// Associated [`Surface`](trait.Surface.html) of this `Device` type
type Surface: Surface; type Surface: Surface;
/// Returns the `id` of this device node.
fn device_id(&self) -> dev_t; fn device_id(&self) -> dev_t;
/// Assigns a `DeviceHandler` called during event processing.
///
/// See [`device_bind`](fn.device_bind.html) and [`DeviceHandler`](trait.DeviceHandler.html)
fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static); fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static);
/// Clear a set [`DeviceHandler`](trait.DeviceHandler.html), if any
fn clear_handler(&mut self); fn clear_handler(&mut self);
/// Creates a new rendering surface.
///
/// Initialization of surfaces happens through the types provided by
/// [`drm-rs`](https://docs.rs/drm/0.3.4/drm/).
///
/// [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)s represent scanout engines
/// of the device pointer to one framebuffer.
/// Their responsibility is to read the data of the framebuffer and export it into an "Encoder".
/// The number of crtc's represent the number of independant output devices the hardware may handle.
fn create_surface( fn create_surface(
&mut self, &mut self,
ctrc: crtc::Handle, ctrc: crtc::Handle,
) -> Result<Self::Surface, <Self::Surface as Surface>::Error>; ) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;
/// Processes any open events of the underlying file descriptor.
///
/// You should not call this function manually, but rather use
/// [`device_bind`](fn.device_bind.html) to register the device
/// to an [`EventLoop`](https://docs.rs/calloop/0.4.2/calloop/struct.EventLoop.html)
/// to synchronize your rendering to the vblank events of the open crtc's
fn process_events(&mut self); fn process_events(&mut self);
/// Load the resource from a `Device` given its
/// [`ResourceHandle`](https://docs.rs/drm/0.3.4/drm/control/trait.ResourceHandle.html)
fn resource_info<T: ResourceInfo>( fn resource_info<T: ResourceInfo>(
&self, &self,
handle: T::Handle, handle: T::Handle,
) -> Result<T, <Self::Surface as Surface>::Error>; ) -> Result<T, <Self::Surface as Surface>::Error>;
/// Attempts to acquire a copy of the `Device`'s
/// [`ResourceHandles`](https://docs.rs/drm/0.3.4/drm/control/struct.ResourceHandles.html)
fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error>; fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error>;
} }
/// Marker trait for `Device`s able to provide [`RawSurface`](trait.RawSurface.html)s
pub trait RawDevice: Device<Surface = <Self as RawDevice>::Surface> { pub trait RawDevice: Device<Surface = <Self as RawDevice>::Surface> {
/// Associated [`RawSurface`](trait.RawSurface.html) of this `RawDevice` type
type Surface: RawSurface; type Surface: RawSurface;
} }
/// An open crtc that can be used for rendering
pub trait Surface { pub trait Surface {
/// Type repesenting a collection of
/// [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s
/// returned by [`current_connectors`](#method.current_connectors) and
/// [`pending_connectors`](#method.pending_connectors)
type Connectors: IntoIterator<Item = connector::Handle>; type Connectors: IntoIterator<Item = connector::Handle>;
/// Error type returned by methods of this trait
type Error: Error + Send; type Error: Error + Send;
/// Returns the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) of this surface
fn crtc(&self) -> crtc::Handle; fn crtc(&self) -> crtc::Handle;
/// Currently used [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s of this `Surface`
fn current_connectors(&self) -> Self::Connectors; fn current_connectors(&self) -> Self::Connectors;
/// Returns the pending [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s
/// used after the next `commit` of this `Surface`
///
/// *Note*: Only on a [`RawSurface`](trait.RawSurface.html) you may directly trigger
/// a [`commit`](trait.RawSurface.html#method.commit). Other `Surface`s provide their
/// own methods that *may* trigger a commit, you will need to read their docs.
fn pending_connectors(&self) -> Self::Connectors; fn pending_connectors(&self) -> Self::Connectors;
/// Tries to add a new [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)
/// to be used after the next commit.
///
/// Fails if the `connector` is not compatible with the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)
/// (e.g. no suitable [`encoder`](https://docs.rs/drm/0.3.4/drm/control/encoder/index.html) may be found)
/// or is not compatible with the currently pending
/// [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html).
fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
/// Tries to mark a [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)
/// for removal on the next commit.
fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
/// Returns the currently active [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html)
/// of the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)
/// if any.
fn current_mode(&self) -> Option<Mode>; fn current_mode(&self) -> Option<Mode>;
/// Returns the currently pending [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html)
/// to be used after the next commit, if any.
fn pending_mode(&self) -> Option<Mode>; fn pending_mode(&self) -> Option<Mode>;
/// Tries to set a new [`Mode`](https://docs.rs/drm/0.3.4/drm/control/struct.Mode.html)
/// to be used after the next commit.
///
/// Fails if the mode is not compatible with the underlying
/// [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html) or any of the
/// pending [`connector`](https://docs.rs/drm/0.3.4/drm/control/connector/index.html)s.
///
/// *Note*: Only on a [`RawSurface`](trait.RawSurface.html) you may directly trigger
/// a [`commit`](trait.RawSurface.html#method.commit). Other `Surface`s provide their
/// own methods that *may* trigger a commit, you will need to read their docs.
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error>; fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error>;
} }
/// An open bare crtc without any rendering abstractions
pub trait RawSurface: Surface + ControlDevice + BasicDevice { pub trait RawSurface: Surface + ControlDevice + BasicDevice {
/// Returns true whenever any state changes are pending to be commited
///
/// The following functions may trigger a pending commit:
/// - [`add_connector`](trait.Surface.html#method.add_connector)
/// - [`remove_connector`](trait.Surface.html#method.remove_connector)
/// - [`use_mode`](trait.Surface.html#method.use_mode)
fn commit_pending(&self) -> bool; fn commit_pending(&self) -> bool;
/// Commit the pending state rendering a given framebuffer.
///
/// *Note*: This will trigger a full modeset on the underlying device,
/// potentially causing some flickering. Check before performing this
/// operation if a commit really is necessary using [`commit_pending`](#method.commit_pending).
///
/// This operation is blocking until the crtc is in the desired state.
fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>; fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
/// Page-flip the underlying [`crtc`](https://docs.rs/drm/0.3.4/drm/control/crtc/index.html)
/// to a new given [`framebuffer`].
///
/// This will not cause the crtc to modeset.
///
/// This operation is not blocking and will produce a `vblank` event once swapping is done.
/// Make sure to [set a `DeviceHandler`](trait.Device.html#method.set_handler) and
/// [register the belonging `Device`](fn.device_bind.html) before to receive the event in time.
fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>; fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), SwapBuffersError>;
} }
/// Trait for types representing open devices /// Trait representing open devices that *may* return a `Path`
pub trait DevPath { pub trait DevPath {
/// Returns the path of the open device if possible /// Returns the path of the open device if possible
fn dev_path(&self) -> Option<PathBuf>; fn dev_path(&self) -> Option<PathBuf>;
@ -87,7 +224,8 @@ impl<A: AsRawFd> DevPath for A {
/// Bind a `Device` to an `EventLoop`, /// Bind a `Device` to an `EventLoop`,
/// ///
/// This will cause it to recieve events and feed them into an `DeviceHandler` /// This will cause it to recieve events and feed them into a previously
/// set [`DeviceHandler`](trait.DeviceHandler.html).
pub fn device_bind<D: Device + 'static, Data>( pub fn device_bind<D: Device + 'static, Data>(
handle: &LoopHandle<Data>, handle: &LoopHandle<Data>,
device: D, device: D,