<NME> mod.rs
<BEF> //! This module represents abstraction on top the linux direct rendering manager api (drm).
//!
//! ## [`DrmDevice`]
//!
//! A device exposes certain properties, which are directly derived
//! from the *device* as perceived by the direct rendering manager api (drm). These resources consists
//! out of connectors, encoders, framebuffers, planes and crtcs.
//!
//! [`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".
//! The number of crtc's represent the number of independent output devices the hardware may handle.
//!
//! On modern graphic cards it is better to think about the `crtc` as some sort of rendering engine.
//! 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.
//! Also not every encoder might be connected to every crtc.
//!
//! A [`connector`](drm::control::connector) represents a port on your computer, possibly with a connected monitor, TV, capture card, etc.
//!
//! A [`framebuffer`](drm::control::framebuffer) represents a buffer you may display, see `DrmSurface` below.
//!
//! A [`plane`](drm::control::plane) adds 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. Planes have to be explicitly used by the user to be useful.
//! Every device has at least one primary plane used to display an image to the whole crtc. Additionally cursor and overlay planes may be present.
//! Cursor planes are usually very restricted in size and meant to be used for hardware cursors, while overlay planes may
//! be used for performance reasons to display any overlay on top of the image, e.g. the top-most windows.
//! Overlay planes may have a bunch of weird limitation, that you cannot query, e.g. only working on round pixel coordinates.
//! You code should never rely on a fixed set of overlay planes, but always have a fallback solution in place.
//!
//! 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), a plane,
//! as well as a `Mode` and a set of `connectors`.
//!
//! 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
//! The drm infrastructure makes no assumptions about the used renderer and does not interface with them directly.
//! It just provides a way to create framebuffers from various buffer types (mainly `DumbBuffer`s and hardware-backed gbm `BufferObject`s).
//!
//! Buffer management and details about the various types can be found in the [`allocator`-Module](crate::backend::allocator) and
//! rendering abstractions, which can target these buffers can be found in the [`renderer`-Module](crate::backend::renderer).
//!
//! ## [`DrmNode`]
//!
//! A drm node refers to a drm device and the capabilities that may be performed using the node.
//! Generally [`DrmNode`] is primarily used by clients (such as the output backends) which need
//! to allocate buffers for use in X11 or Wayland. If you need to do mode setting, you should use
//! [`DrmDevice`] instead.

pub(crate) mod device;
//!     .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];
#[derive(Debug)]
pub struct Planes {
    /// The primary plane of the crtc (automatically selected for [DrmDevice::create_surface])
    pub primary: plane::Handle,
//!         mode,
//!         vec![connector_info.handle()]
//!     ).unwrap();
//! # }
//! ```
//!

    let planes = dev.plane_handles().map_err(|source| DrmError::Access {
        errmsg: "Error loading plane handles",
        dev: dev.dev_path(),
        source,
    })?;

    let resources = dev.resource_handles().map_err(|source| DrmError::Access {
        errmsg: "Error loading resource handles",
        dev: dev.dev_path(),
        source,
    })?;

    for plane in planes {
        let info = dev.get_plane(plane).map_err(|source| DrmError::Access {
            errmsg: "Failed to get plane information",
            dev: dev.dev_path(),
            source,
        })?;
        let filter = info.possible_crtcs();
        if resources.filter_crtcs(filter).contains(crtc) {
            match plane_type(dev, plane)? {
                PlaneType::Primary => {
                    primary = Some(plane);
                }
                PlaneType::Cursor => {
                    cursor = Some(plane);
                }
                PlaneType::Overlay => {
                    overlay.push(plane);
                }
            };
        }
    }

    Ok(Planes {
        primary: primary.expect("Crtc has no primary plane"),
//! #     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())
        errmsg: "Failed to get properties of plane",
        dev: dev.dev_path(),
        source,
    })?;
    let (ids, vals) = props.as_props_and_values();
    for (&id, &val) in ids.iter().zip(vals.iter()) {
        let info = dev.get_property(id).map_err(|source| DrmError::Access {
            errmsg: "Failed to get property info",
            dev: dev.dev_path(),
            source,
        })?;
        if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
            return Ok(match val {
                x if x == (PlaneType::Primary as u64) => PlaneType::Primary,
                x if x == (PlaneType::Cursor as u64) => PlaneType::Cursor,
                _ => PlaneType::Overlay,
            });
        }
    }
    unreachable!()
}

<MSG> Do a better job at finding a crtc in the example

<DFF> @@ -39,15 +39,20 @@
 //! You will need to use the `drm` crate to provide the required types to create
 //! a backend.
 //!
-//! ```rust,ignore
+//! ```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 drm::control::encoder::{Info as EncoderInfo};
+//! # use std::io::Error as IoError;
 //! use std::fs::OpenOptions;
+//! # use std::time::Duration;
 //! use smithay::backend::drm::DrmDevice;
+//! # use smithay::backend::drm::{DrmHandler, Id};
+//! # use wayland_server::EventLoopHandle;
 //!
 //! # fn main() {
 //! // Open the drm device
@@ -68,8 +73,17 @@
 //!     .find(|conn| conn.connection_state() == ConnectorState::Connected)
 //!     .unwrap();
 //!
-//! // Use first crtc (should be successful in most cases)
-//! let crtc = res_handles.crtcs()[0];
+//! // Use the first encoder
+//! let encoder_info = EncoderInfo::load_from_device(&device, connector_info.encoders()[0]).unwrap();
+//!
+//! // use the connected crtc if any
+//! let crtc = encoder_info.current_crtc()
+//!     // or use the first one that is compatible with the encoder
+//!     .unwrap_or_else(||
+//!         *res_handles.crtcs()
+//!         .iter()
+//!         .find(|crtc| encoder_info.supports_crtc(**crtc))
+//!         .unwrap());
 //!
 //! // Use first mode (usually the highest resolution)
 //! let mode = connector_info.modes()[0];
@@ -80,6 +94,14 @@
 //!         mode,
 //!         vec![connector_info.handle()]
 //!     ).unwrap();
+//! # struct MyDrmHandler;
+//! #
+//! # impl DrmHandler for MyDrmHandler {
+//! #    fn ready(&mut self, _: &mut EventLoopHandle, id: Id, _frame: u32, _duration: Duration) {}
+//! #    fn error(&mut self, _: &mut EventLoopHandle, error: IoError) {}
+//! # }
+//! #
+//! # device.set_handler(MyDrmHandler);
 //! # }
 //! ```
 //!
@@ -123,6 +145,7 @@
 //! #     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())

Do a better job at finding a crtc in the example