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§
- Framebuffer
Grab 🔒 - 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.
- Shared
Framebuffer 🔒 - A watch on the framebuffer of the screen of one root window (module docblock).
- Watch
Reply 🔒 - The reply to Watch: the three fds and the framebuffer’s geometry.
Enums§
- Opened 🔒
- What
SharedFramebuffer::openfound: 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_THREADSthreads (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, andarmed, and of its bitmap. - WATCH_
TILES_ 🔒X - WATCH_
TILES_ 🔒Y