denise-drm
The Linux DRM/KMS backend for Denise — and the primary target the whole toolkit exists for.
Opens the display directly, sets a mode, and page-flips CPU-rendered dumb buffers straight to the scanout engine. No compositor, no window server, no GPU driver stack, no X. One static binary that owns the panel.
#
#
DrmSurface::new(card, config) takes a Card you opened yourself — including one
handed over as a file descriptor, which is how this coexists with libseat or a
systemd unit.
Becoming DRM master
Setting a mode requires being DRM master, and only one process can be. If a
compositor or another Denise process holds it, Card::become_master fails with
EBUSY or EACCES — the single most common reason a first run on a Pi does
nothing. Three ways to have the right:
- Run on a bare VT with no display server. The usual kiosk deployment.
- Be handed a file descriptor by
libseator a systemd unit, viaCard::from_fd. Preferred for anything that has to coexist. - Run as root. Works, and is a poor way to ship a product.
What it deliberately does not do
No gbm. GBM exists to allocate buffers a GPU renders into. Denise renders
with the CPU, so DRM dumb buffers are exactly the right allocation: scanout-capable,
CPU-mappable, and free of any C library. Adding GBM would drag in libgbm and Mesa,
ending both the single-static-binary goal and easy cross-compilation.
No atomic modesetting, yet. Atomic buys FB_DAMAGE_CLIPS, plane composition
and tear-free guarantees. The first is worth little here — a page flip swaps whole
buffers, so damage saves rasterisation, not bandwidth, and most drivers ignore the
property. The second has a legacy equivalent for the one plane that matters, the
hardware cursor. So the legacy path gets this working on real hardware at a third
of the code, behind a seam atomic can take over when planes earn their keep.
Testing
Mode selection and the swapchain are platform-independent on purpose and are unit tested everywhere, including on machines with no DRM device. They hold the decisions that are hard to debug in the field and easy to check on a laptop. Everything else is a thin wrapper over ioctls and can only be proven on real hardware — which it has been, on a Raspberry Pi.
Two examples help on a new board: probe prints the connectors, modes and
capabilities it finds, and smoke sets a mode and flips.
Platform
Linux only. On any other target the crate compiles to almost nothing, which is what
lets the whole workspace be checked and published from one runner. unsafe is
permitted here and every block carries a // SAFETY: comment.
Where this sits
Implements denise::Surface. Pair it with
denise-evdev for input — both expose raw
file descriptors, so an event loop can epoll on input and vblank together and the
process idles in the kernel rather than spinning.
denise-fbdev is the fallback for kernels
with no usable DRM driver.
Status
M2 complete, running on real hardware. Part of Denise — see the repository README and docs/design.md for the whole picture.
MIT licensed.