Skip to main content

drmkit_capture/
lib.rs

1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! Read back what a CRTC is scanning out, and write it to a file.
5//!
6//! [`snapshot()`] composites the planes bound to a CRTC into an [`Image`] the
7//! size of its active mode, reading each plane's buffer back through a
8//! dma-buf. [`write_png`] puts one on disk.
9//!
10//! This is a readback path, not a rendering one: it reads buffers that already
11//! exist and blends them on the CPU as the display controller would, for
12//! planes that are neither cropped nor scaled.
13//! What it cannot read -- tiled buffers, YUV, anything not host-mappable -- it
14//! skips with a warning rather than failing the capture, because a screenshot
15//! missing its video overlay is more use than no screenshot.
16
17mod image;
18#[cfg(feature = "jpeg")]
19mod jpg;
20mod png;
21mod snapshot;
22
23#[cfg(test)]
24mod tests;
25
26pub use image::{Image, src_over, unpremultiply};
27#[cfg(feature = "jpeg")]
28pub use jpg::{Nv12Frame, write_jpg, write_jpg_nv12};
29pub use png::write_png;
30pub use snapshot::snapshot;
31
32/// What can go wrong capturing or writing a frame.
33#[derive(Debug, thiserror::Error)]
34#[non_exhaustive]
35pub enum CaptureError {
36    /// The CRTC is not driving a mode, so there is no size to capture at.
37    #[error("the CRTC is not driving a mode")]
38    NoMode,
39
40    /// No plane on the CRTC could be read.
41    ///
42    /// Either the CRTC really is blank, or every plane on it was skipped --
43    /// see [`snapshot()`] for what gets skipped, and note that a client which
44    /// has not enabled the atomic cap cannot see plane geometry at all.
45    #[error("no plane on the CRTC could be read back")]
46    NothingReadable,
47
48    /// The image has no pixels.
49    #[error("the image is empty")]
50    EmptyImage,
51
52    /// The kernel or the filesystem refused.
53    #[error("io: {0}")]
54    Io(#[source] std::io::Error),
55}