Skip to main content

Module framebuffer

Module framebuffer 

Source
Expand description

The screen read where the X server keeps it: SELKIES-FRAMEBUFFER, which the Selkies images’ Xvfb offers for a screen held in system memory, in place of XShm’s per-frame copy and XDamage’s round trips.

The server keeps the screen in a memfd it hands over read-only, and hands each watch a memfd of its own and an eventfd: the watch is a bitmap of the TILE x TILE tiles drawn into since the client last cleared them, which the server sets as it draws, and armed, which the client sets before it waits on the eventfd and the server clears as it signals once a drawing operation ends. A frame is then the tiles drawn since the surface it lands in last held the screen: the capture’s pool rotates its surfaces, so each keeps the tiles it is missing (FramebufferGrab), and the cursor and the watermark composited onto one count among them. The server sets a tile for every drawing that reaches the screen, so the tiles drawn since the last frame, with the overlays that moved or changed their image, are the frame’s whole change, which the pipeline takes in place of a content hash.

The framebuffer’s head counts drawing operations, odd while one runs, so a read is whole where the count stood even before it and unchanged after it; one an operation ran across reads again what that operation drew, and a frame that cannot get a whole read in READ_ATTEMPTS is grabbed through XShm, which the server answers between operations. A resize moves the screen to a framebuffer of its new size and retires the old one, which says so in its head and signals the watch; the capture then watches again.

A session whose encoder takes 8-bit 4:2:0 planes (X11Pipeline::takes_host_planes, x264) skips the copy: each pool surface’s planes, NV12 laid out as x264 encodes it in place (Nv12Planes), are brought up to the screen by converting the rows of tiles they miss straight from the framebuffer, under the same drawing count (FramebufferGrab::convert), so the pixels are read once, by the conversion, where a copy read and wrote them first: a full-screen change at 2560x1600 took 0.85 ms to convert in place against 1.4 ms to copy and 0.67 ms more to convert. The rows are converted across the region’s whole width, as the planes are row-major. The tiles a surface misses are the same set either way, so a capture switching between its pixels and its planes (an overlay drawn onto the pixels comes or goes) starts both over from the whole screen.

The path is taken only where the server answers the request, the framebuffer is sealed against shrinking (a mapping a shrink cut short would fault the read), its head agrees with the reply, and its pixels match what GetImage returns: that the extension is there is not proof the memory holds the screen.

Structs§

FramebufferGrab 🔒
The capture’s watch, the tiles each pool surface is missing (module docblock), and those drawn since the last frame said where it changed (changed).
Mapping 🔒
A shared mapping, unmapped on drop.
SharedFramebuffer 🔒
A watch on the framebuffer of the screen of one root window (module docblock).
WatchReply 🔒
The reply to Watch: the three fds and the framebuffer’s geometry.

Enums§

Opened 🔒
What SharedFramebuffer::open found: a watch, or why there is none.

Constants§

COPY_THREADS 🔒
Threads a large copy runs on, the capture thread among them: a copy is bound by memory bandwidth, which a few threads fill.
DRAW_WAIT 🔒
How long a read waits for a drawing operation under way to end before it gives up on the attempt: an operation is one request’s drawing, well under a millisecond.
EXTENSION 🔒
HEAD_BPP 🔒
HEAD_HEIGHT 🔒
HEAD_RETIRED 🔒
HEAD_SEQ 🔒
HEAD_STRIDE 🔒
HEAD_WIDTH 🔒
Byte offsets of the framebuffer head’s fields the client reads.
MAGIC 🔒
PARALLEL_BYTES 🔒
Bytes of tiles past which a read copies its rows of tiles on COPY_THREADS threads (SharedFramebuffer::copy_tiles); below it, starting them costs more than it saves. Scoped threads of the copy’s own rather than the rayon pool: waking the pool’s every worker for a copy a frame kept them spinning, 1.9 cores more at 2560x1600 and 60 fps.
READ_ATTEMPTS 🔒
Reads a frame tries for a whole one before it is grabbed through XShm instead.
VERSION 🔒
WATCH_ARMED 🔒
WATCH_BITS 🔒
WATCH_TILE 🔒
Byte offsets of the watch’s tile, tiles_x, tiles_y, and armed, and of its bitmap.
WATCH_TILES_X 🔒
WATCH_TILES_Y 🔒