docs: Add a more fleshed out backend::drm module documentation

This commit is contained in:
Victor Brekenfeld 2020-06-05 20:06:17 +02:00
parent 05992b9d11
commit fa42a0a223
5 changed files with 141 additions and 18 deletions

View File

@ -7,6 +7,8 @@
//! //!
//! For an example how to use this standalone, take a look at the raw_atomic_drm example. //! For an example how to use this standalone, take a look at the raw_atomic_drm example.
//! //!
//! For detailed overview of these abstractions take a look at the module documentation of backend::drm.
//!
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;

View File

@ -7,6 +7,8 @@
//! to let your compositor render. //! to let your compositor render.
//! Take a look at `anvil`s source code for an example of this. //! Take a look at `anvil`s source code for an example of this.
//! //!
//! For detailed overview of these abstractions take a look at the module documentation of backend::drm.
//!
use drm::control::{connector, crtc, encoder, framebuffer, plane, Mode, ResourceHandles}; use drm::control::{connector, crtc, encoder, framebuffer, plane, Mode, ResourceHandles};
use drm::SystemError as DrmError; use drm::SystemError as DrmError;

View File

@ -12,6 +12,8 @@
//! [`FallbackDevice`](::backend::drm::common::fallback::FallbackDevice). //! [`FallbackDevice`](::backend::drm::common::fallback::FallbackDevice).
//! Take a look at `anvil`s source code for an example of this. //! Take a look at `anvil`s source code for an example of this.
//! //!
//! For detailed overview of these abstractions take a look at the module documentation of backend::drm.
//!
use super::{Device, DeviceHandler, RawDevice, Surface}; use super::{Device, DeviceHandler, RawDevice, Surface};

View File

@ -8,6 +8,8 @@
//! To use these types standalone, you will need to consider the special requirements //! To use these types standalone, you will need to consider the special requirements
//! of [`GbmSurface::page_flip`](::backend::drm::gbm::GbmSurface::page_flip). //! of [`GbmSurface::page_flip`](::backend::drm::gbm::GbmSurface::page_flip).
//! //!
//! For detailed overview of these abstractions take a look at the module documentation of backend::drm.
//!
use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface}; use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
use crate::backend::graphics::SwapBuffersError; use crate::backend::graphics::SwapBuffersError;

View File

@ -1,38 +1,153 @@
//! //!
//!
//! This module provides Traits reprensentating open devices //! This module provides Traits reprensentating open devices
//! and their surfaces to render contents. //! and their surfaces to render contents.
//! //!
//! --- //! # Abstractions
//! //!
//! Initialization of devices happens through an open file descriptor //! This is a model of what the user typically perceives as a `Device` and a `Surface`.
//! of a drm device. //! The meaning of these words is very overloaded in the general computer graphics context,
//! so let me give you a quick run down, what these mean in the context of smithay's public api:
//! //!
//! --- //! ## Device
//! //!
//! Initialization of surfaces happens through the types provided by //! A device is some sort of rendering device. It exposes certain properties, which are directly derived
//! [`drm-rs`](drm). //! from the *device* as perceived by the direct rendering manager api (drm). These resources consists
//! out of connectors, encoders, framebuffers, planes and crtcs.
//! //!
//! Four entities are relevant for the initialization procedure. //! [`crtc`](drm::control::crtc)s represent scanout engines of the device pointer to one framebuffer.
//!
//! [`crtc`](drm::control::crtc)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". //! 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. //! The number of crtc's represent the number of independent output devices the hardware may handle.
//! //!
//! An [`encoder`](drm::control::encoder) encodes the data of //! On modern graphic cards it is better to think about the `crtc` as some sort of rendering engine.
//! connected crtcs into a video signal for a fixed set of connectors. //! You can only have so many different pictures, you may display, as you have `crtc`s, but a single image
//! may be put onto multiple displays.
//!
//! An [`encoder`](drm::control::encoder) 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. //! 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. //! Also not every encoder might be connected to every crtc.
//! //!
//! A [`connector`](drm::control::connector) represents a port //! A [`connector`](drm::control::connector) represents a port on your computer, possibly with a connected monitor, TV, capture card, etc.
//! on your computer, possibly with a connected monitor, TV, capture card, etc. //!
//! A [`framebuffer`](drm::control::framebuffer) represents a buffer you may be rendering to, see `Surface` below.
//!
//! Planes are another layer on top of the crtcs, which allow us to layer multiple images on top of each other more efficiently
//! then by combining the rendered images in the rendering phase, e.g. via OpenGL. They are internally used by smithay to provide
//! hardware-accelerated cursors. More features regarding planes may be added in the future, but they are mostly optional and
//! mainly provide possibilies for optimizations.
//!
//! The main functionality of a `Device` in smithay is to give access to all these properties for the user to
//! choose an appropriate rendering configuration. What that means is defined by the requirements and constraints documented
//! in the specific device implementations. The second functionality is the creation of a `Surface`.
//! Surface creation requires a `crtc` (which cannot be the same as another existing `Surface`'s crtc),
//! as well as a `Mode` and a set of `connectors`.
//!
//! smithay does not make sure that `connectors` are not already in use by another `Surface`. Overlapping `connector`-Sets may
//! be an error or result in undefined rendering behavior depending on the `Surface` implementation.
//!
//! ## Surface
//!
//! A surface is a part of a `Device` that may output a picture to a number of connectors. It pumps pictures of buffers to outputs.
//! //!
//! On surface creation a matching encoder for your `encoder`-`connector` is automatically selected, //! 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. //! if it exists, which means you still need to check your configuration.
//! //!
//! At last a [`Mode`](drm::control::Mode) needs to be selected, //! A surface consists of one `crtc` that is rendered to by the user. This is fixed for the `Surface`s lifetime and cannot be changed.
//! supported by the `crtc` in question. //! A surface also always needs at least one connector to output the resulting image to as well as a `Mode` that is valid for the given connector.
//!
//! The state of a `Surface` is double-buffered, meaning all operations that chance the set of `connector`s or their `Mode` are stored and
//! only applied on the next commit. `Surface`s do their best to validate these changes, if possible.
//!
//! A commit/page_flip may be triggered by any other method the `Surface` has, but needs to be documented as such.
//! The most low-level `Surface`s also implement `RawSurface`, which let you trigger a commit explicitly.
//!
//! ## RawDevice
//!
//! A low-level device that produces not only `Surface`s, but `RawSurface`s.
//!
//! ## RawSurface
//!
//! RawSurfaces provide two additional functions related to rendering: `commit` and `page_flip`.
//! Both attach the contents of a framebuffer, resulting in it's contents being displayed on the set connectors.
//!
//! `commit` also applies any pending changes to the current `Mode` and `connector`-Sets.
//! You can easily check, if there are pending changes and avoid the costly commit by using `commit_pending`,
//! which compares the current and pending state internally.
//!
//! # Rendering
//!
//! To perform actual rendering operations you need to render your image to a framebuffer.
//! Several types of framebuffers exists.
//!
//! The simplest one - the `Dumbbuffer` is a simple bitmap, usually very slow and not hardware-accelerated.
//! It should be avoided at any cost, but works on all devices and can be used directly with a `RawSurface`.
//! Rendering to it can be done manually by coping bitmaps around (cpu rendering).
//!
//! Accelerated buffers are usually hardware manufacturer dependent. A problem, which is mostly solved by
//! the General Buffer Manager (gbm-)API. `gbm::Buffer`s can only be rendered to by egl. Appropriate hardware-accelerated
//! buffers are picked automatically. gbm even may fall back to `Dumbbuffers` on unsupported devices and
//! egl-support is then provided by Mesa's software renderer `llvmpipe`.
//!
//! An alternative api to `gbm` is the so called `eglstream`-api, proposed (and implemented) by nvidia.
//! It is currenly only supported by nvidias proprietary driver, which is also not accelerated by gbm, although other
//! manufacturers could in theory implement the standard, just like nvidia could implement gbm-support in their driver.
//! Ongoing discussions about these api's may result in another (but hopefully unified) api in the future.
//!
//! # Implementations
//!
//! Smithay provided these different functionalities as wrappers around many `Device` and `Surface` implementations.
//!
//! At the low-level we have:
//!
//! - [`AtomicDrmDevice`](atomic::AtomicDrmDevice) (and [`AtomicDrmSurface`](atomic::AtomicDrmSurface)), which implement the traits directly using the modern atomic drm-api.
//! - [`LegacyDrmDevice`](legacy::LegacyDrmDevice) (and [`LegacyDrmSurface`](legacy::LegacyDrmSurface)), which implement the traits directly using the outdated drm-api.
//!
//! Both of these also implement `RawDevice` and `RawSurface`.
//!
//! On top of that the following wrappers add buffer allocation apis:
//!
//! - [`GbmDevice`](gbm::GbmDevice) (and [`GbmSurface`](gbm::Surface)), which replace the direct rendering capabilities of any underlying `RawSurface` with an egl-specific `page_flip` function.
//! - [`EglStreamDevice`](eglstream::EglStreamDevice) (and [`EglStreamSurface`](eglstream::EglStreamSurface)), which replace the direct rendering capabilities of any underlying `RawSurface` with functionality to create EGLStreams.
//!
//! On top of that the [`EglDevice`](egl::EglDevice) (and [`EglSurface`](egl::EglSurface)) replace the manual buffer management
//! with an implementation of smithays [`GLGraphicsBackend`](::backend::graphics::gl::GLGraphicsBackend) to initialize the OpenGL-API for rendering.
//!
//! Additionally the [`FallbackDevice`](fallback::FallbackDevice) provides an easy wrapper to automatically pick an appropriate device.
//! E.g. it can initialize an `AtomicDrmDevice` or fallback to a `LegacyDrmDevice` with the atomic api is not supported by the graphics card.
//! It can also check for a loaded nvidia-driver for a given device and choose between an `EglStreamDevice` or a `GbmDevice`.
//!
//! Any layer of this chain can be implemented and therefore extended by the user. All building blocks are exposed to add addtional
//! buffer management solutions or rendering apis out of tree. Additionally all of these implementations can be excluded from a build
//! by disabling their corresponding feature.
//!
//! The most versatile type currently provided by smithay, that should be able to initialize almost every
//! common graphics card is
//! ```rust,ignore
//! type RenderDevice<A: AsRawFd> = FallbackDevice<
//! EglDevice<
//! EglGbmBackend<FallbackDevice<AtomicDrmDevice<A>, LegacyDrmDevice<A>>>,
//! GbmDevice<FallbackDevice<AtomicDrmDevice<A>, LegacyDrmDevice<A>>>,
//! >,
//! EglDevice<
//! EglStreamDeviceBackend<FallbackDevice<AtomicDrmDevice<A>, LegacyDrmDevice<A>>>,
//! EglStreamDevice<FallbackDevice<AtomicDrmDevice<A>, LegacyDrmDevice<A>>>,
//! >
//! >;
//! ```
//!
//! # Event handling
//!
//! Devices can be attached to an eventloop using `device_bind`.
//! Events triggered by a drm-device correspond to finished page-flips.
//! After submitting a page_flip (possibly through a high-level api, such as a `EglSurface`)
//! the GPU may take some time until the new framebuffer is displayed. Rendering the next
//! frame should be delayed until the flip is done.
//!
//! Naive implementations should thus be driven by the drm device events to synchronize rendering
//! with the device. More advanced implementations may take into account that, if no change has occurred,
//! a page_flip may waste resources and therefore delay rendering until the buffer change from a client
//! is received or input is registered, etc. Because a flip may fail (which will result in no event),
//! a robust rescheduling implementation for missed frames or intentionally skipped flips should be
//! in place.
//! //!
use drm::{ use drm::{