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 exactly as the display controller would.
12//! What it cannot read -- tiled buffers, YUV, anything not host-mappable -- it
13//! skips with a warning rather than failing the capture, because a screenshot
14//! missing its video overlay is more use than no screenshot.
15
16mod image;
17#[cfg(feature = "jpeg")]
18mod jpg;
19mod png;
20mod snapshot;
21
22#[cfg(test)]
23mod tests;
24
25pub use image::{Image, src_over, unpremultiply};
26#[cfg(feature = "jpeg")]
27pub use jpg::{Nv12Frame, write_jpg, write_jpg_nv12};
28pub use png::write_png;
29pub use snapshot::snapshot;
30
31/// What can go wrong capturing or writing a frame.
32#[derive(Debug, thiserror::Error)]
33#[non_exhaustive]
34pub enum CaptureError {
35 /// The CRTC is not driving a mode, so there is no size to capture at.
36 #[error("the CRTC is not driving a mode")]
37 NoMode,
38
39 /// No plane on the CRTC could be read.
40 ///
41 /// Either the CRTC really is blank, or every plane on it was skipped --
42 /// see [`snapshot`] for what gets skipped, and note that a client which
43 /// has not enabled the atomic cap cannot see plane geometry at all.
44 #[error("no plane on the CRTC could be read back")]
45 NothingReadable,
46
47 /// The image has no pixels.
48 #[error("the image is empty")]
49 EmptyImage,
50
51 /// The kernel or the filesystem refused.
52 #[error("io: {0}")]
53 Io(#[source] std::io::Error),
54}