Skip to main content

denise_drm/
error.rs

1//! Failures from the DRM backend.
2
3use std::fmt;
4use std::io;
5use std::path::PathBuf;
6
7use denise::SurfaceError;
8
9use crate::mode::SelectionError;
10
11/// Something went wrong talking to the display.
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum DrmError {
15    /// `/dev/dri` holds no card node.
16    NoDevice,
17
18    /// A card node could not be opened.
19    Open {
20        /// The device that failed.
21        path: PathBuf,
22        /// The underlying failure.
23        source: io::Error,
24    },
25
26    /// Every card node was opened but none can drive a display.
27    ///
28    /// Usually means only render nodes are present — a headless GPU, or a card
29    /// whose display side is claimed by another driver.
30    NoDisplayCapableDevice,
31
32    /// This process could not become DRM master.
33    ///
34    /// Only one process at a time may set modes. See the crate documentation: run
35    /// on a bare VT, or take a descriptor from `libseat` or systemd.
36    NotMaster(io::Error),
37
38    /// Enumerating connectors, encoders and CRTCs failed.
39    Resources(io::Error),
40
41    /// No output could be chosen.
42    Selection(SelectionError),
43
44    /// The chosen connector has no CRTC that can drive it.
45    NoCrtc {
46        /// The connector id that could not be routed.
47        connector: u32,
48    },
49
50    /// A scanout buffer could not be allocated.
51    Allocate {
52        /// Requested width.
53        width: u32,
54        /// Requested height.
55        height: u32,
56        /// The underlying failure.
57        source: io::Error,
58    },
59
60    /// A scanout buffer could not be mapped into this process.
61    Map(io::Error),
62
63    /// The driver handed back a row pitch that is not a whole number of pixels.
64    ///
65    /// Denise addresses buffers as `u32` words, so a pitch that is not a multiple
66    /// of four bytes cannot be expressed as a pixel stride.
67    UnalignedPitch {
68        /// The pitch the driver reported, in bytes.
69        pitch: u32,
70    },
71
72    /// Attaching a buffer to the display failed.
73    AddFramebuffer(io::Error),
74
75    /// Setting the mode failed.
76    SetMode {
77        /// The mode that was attempted.
78        mode: String,
79        /// The CRTC id.
80        crtc: u32,
81        /// The underlying failure.
82        source: io::Error,
83    },
84
85    /// Queueing a page flip failed.
86    PageFlip(io::Error),
87
88    /// Waiting for the flip to complete failed.
89    WaitVblank(io::Error),
90}
91
92impl fmt::Display for DrmError {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match self {
95            Self::NoDevice => f.write_str("no DRM device found under /dev/dri"),
96            Self::Open { path, .. } => write!(f, "opening {}", path.display()),
97            Self::NoDisplayCapableDevice => f.write_str("no DRM device has a display output"),
98            Self::NotMaster(_) => f.write_str(
99                "cannot become DRM master — another process (a compositor, or another \
100                 instance of this program) already holds it, or this process lacks the rights",
101            ),
102            Self::Resources(_) => f.write_str("reading DRM resources"),
103            Self::Selection(err) => core::fmt::Display::fmt(err, f),
104            Self::NoCrtc { connector } => write!(f, "no CRTC can drive connector {connector}"),
105            Self::Allocate { width, height, .. } => {
106                write!(f, "allocating a {width}x{height} dumb buffer")
107            }
108            Self::Map(_) => f.write_str("mapping a dumb buffer"),
109            Self::UnalignedPitch { pitch } => write!(
110                f,
111                "dumb buffer pitch {pitch} is not a whole number of 32-bit pixels"
112            ),
113            Self::AddFramebuffer(_) => f.write_str("registering a framebuffer"),
114            Self::SetMode { mode, crtc, .. } => write!(f, "setting mode {mode} on CRTC {crtc}"),
115            Self::PageFlip(_) => f.write_str("queueing a page flip"),
116            Self::WaitVblank(_) => f.write_str("waiting for vblank"),
117        }
118    }
119}
120
121impl std::error::Error for DrmError {
122    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123        match self {
124            Self::Open { source, .. }
125            | Self::Allocate { source, .. }
126            | Self::SetMode { source, .. }
127            | Self::NotMaster(source)
128            | Self::Resources(source)
129            | Self::Map(source)
130            | Self::AddFramebuffer(source)
131            | Self::PageFlip(source)
132            | Self::WaitVblank(source) => Some(source),
133            Self::NoDevice
134            | Self::NoDisplayCapableDevice
135            | Self::Selection(_)
136            | Self::NoCrtc { .. }
137            | Self::UnalignedPitch { .. } => None,
138        }
139    }
140}
141
142impl From<SelectionError> for DrmError {
143    fn from(err: SelectionError) -> Self {
144        Self::Selection(err)
145    }
146}
147
148impl From<DrmError> for SurfaceError {
149    fn from(err: DrmError) -> Self {
150        SurfaceError::backend(err)
151    }
152}