DRM console display — a placement of a canvas on a DRM/KMS device.
The console twin of term.gfx.display: the same duck-typed contract
(update/show/hide/destroy/set_anchor), but each :update() blits
the canvas surface into a dumb buffer (term.drm_core) and presents it
with a vsynced page flip instead of transmitting it over the Kitty
protocol. The canvas is upscaled by the largest INTEGER factor that fits
the display mode — nearest-neighbour, centered, black borders — so pixel
art stays crisp and uniform.
Presentation is double-buffered with one flip in flight: :update() first
waits for the previous flip's completion event (cooperatively, via the LEV
loop — the wait yields, so the display is the frame pacer and motion runs
at the display's refresh), then blits and queues the next flip. The first
:update() has nothing pending, so creating the display needs no running
LEV loop; every later update must run under one (term.gfx.loop does).
The display manages the controlling console by default: raw mode (no
echoed keystrokes) and a hidden cursor, both restored by :destroy(),
which also restores the CRTC the console was scanning out before. There
is no alt screen and no Kitty handshake — the device is the screen.
Intended to be driven by term.gfx.loop with alt_screen = false and no
input handler (input comes from elsewhere, e.g. evdev).
Opening requires DRM master, so the process must run at a plain VT — a
running compositor holds master and display() returns a clean error.
While the display is live, other VTs cannot repaint (they show a frozen
frame until this process exits); the evdev/VT-gate input layer is what
mutes input meanwhile.
| Name | Signature |
|---|---|
| layout | layout(dev_w, dev_h, cw, ch) -> k, dx, dy |
| display | display(canvas, opts) -> display, err |
layout(
dev_w,dev_h,cw,ch) ->k,dx,dy
Compute the integer-upscale layout of a canvas on a display mode
Returns the largest integer scale factor k such that cw*k x ch*k fits
inside dev_w x dev_h, plus the 0-indexed offsets dx, dy that center the
scaled image. Returns nil, err when the mode is smaller than the canvas
(k < 1).
display(
canvas,opts) ->display,err
Create a DRM console display for a canvas
opts shape:
| Name | Default | Description |
|---|---|---|
path | /dev/dri/card0 | DRM card node |
manage_console | true | raw mode + hidden cursor, restored on destroy |
Returns nil, err (console untouched) when the device can't be opened,
DRM master is unavailable (a compositor is running), no connected output
is found, or the mode is smaller than the canvas.
Methods (the term.gfx.display contract):
:show():update() -- both wait out the pending flip, blit, and flip:hide() -- present a black frame, keep the device open:destroy() -- close the device (restores the CRTC), restore the console:set_anchor() -- no-op (placement is fixed by the display mode)