Skip to main content

Module x11

Module x11 

Source
Expand description

X11/XShm capture loop, stripe dispatch, and per-stripe change detection. X11 host capture: grab the root window into host memory as BGRA, composite the XFixes hardware cursor and the watermark on the CPU, and feed each frame to pipeline::X11Pipeline, which owns damage/stripe/encode. The grab goes through a shared-memory segment (XShm via x11rb) rather than a plain GetImage for one reason: a full-screen frame is far too large to copy through the X protocol socket every tick, so XShm has the server write the pixels straight into memory this process already has mapped.

This is the general path, and it works against any X server. Two zero-copy paths come first where they can serve the session: [dri3] on any server whose screen lives on the GPU has the server blit the root into dmabufs the hardware encoder reads in place, and [nvfbc] on an NVIDIA X server has the driver composite the screen straight into video memory and registers that buffer with NVENC in place. run_capture tries them in that order and falls back here otherwise. Here a server that shares its framebuffer (framebuffer, the images’ Xvfb with the screen in system memory) is read in place, each frame copying only the tiles its surface misses, with no request a frame, and XShm with XDamage serves every other server.

run_capture splits the work across two threads because grabbing the next frame and encoding the previous one have no reason to wait on each other: the caller’s thread grabs frames and owns the x11rb connection and the pool of shm surfaces, while a spawned encode thread owns the pipeline::X11Pipeline (and thus the encoder) and runs the delivery callback, so the two overlap for throughput. Frames hand off through a bounded FramePool that carries only a raw pointer and geometry — never an X object, none of which is safe to share — so nothing X-related ever crosses the thread boundary and the encoder never has to touch X. Multi-instance safety for the encoders is handled inside them (e.g. the libx264 open/close lock); each capture owns its own private xcb connection, so there is no shared X state to serialize here.

Modules§

computer_use
X11 backend for the Computer Use actions: XTEST injection and one-shot root screenshots over a private x11rb connection, so the agent can drive an X session with no active capture and no shared state with any streaming capture thread (the X server itself serializes).
cursor
Out-of-band X11 cursor delivery, the X11 counterpart of the Wayland compositor’s cursor callback: one process-wide monitor thread (the X pointer is global, however many captures run) parks in wait_for_event on its own connection for XFixes DisplayCursorNotify and hands each new cursor to the registered CursorSink — the same payload the Wayland backend sends, so a consumer needs one handler for both. Keeping the cursor out of the framebuffer means pointer motion over static content never dirties the damage hash or re-encodes video; capture_cursor compositing stays available as the opt-in alternative.
dri3
DRI3 zero-copy X11 capture: the X server blits the screen into GPU buffers this process allocated, and the hardware encoder reads them where they lie.
framebuffer 🔒
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.
nvfbc
NVIDIA Framebuffer Capture (NvFBC): the zero-copy X11 capture path, where the NVIDIA driver composites the X screen straight into video memory and NVENC encodes it there.

Structs§

Controls
Cross-thread controls for a running capture: a bag of atomics (plus two mutex-guarded payloads) the owning ScreenCapture pyclass flips from the Python thread and the capture thread reads at the top of each iteration.
FramePool 🔒
Demand-driven capture -> encode handoff: a bounded single-slot channel over a fixed set of pooled shm surfaces.
PoolInner 🔒
Mutex-guarded interior of FramePool: the free-surface index list, the single capture -> encode handoff slot, and the surface the encoder still reads, under one lock so moving a surface between them — acquire, publish, take, recycle, settle — is always a single atomic step.
RawFrame 🔒
A captured raw BGRA frame held in a pooled shm surface, ready to encode.
RootDamage 🔒
The X server’s report that the root window changed, which lets a capture publish a change as it lands instead of on the next tick. None where the server carries no DAMAGE extension, leaving the frame timer to pace the capture by itself.
ShmSurface 🔒
A shared-memory image surface: a POSIX shm segment mapped into both this process and the X server, into which shm_get_image writes one BGRA frame.
VblankClaim 🔒
A running capture’s place in VblankRate, given up when the capture ends.
VblankRate 🔒
The rate the X server’s fake vblank runs at while this process captures it: the fastest live capture’s frame rate, published on the root window as _FAKE_SCREEN_MILLIHZ (CARDINAL, millihertz, 1000 to 1000000) and, rounded to whole frames for servers that read only that, _FAKE_SCREEN_FPS (1 to 1000), both deleted when the last capture ends. The Selkies Xvfb paces the clients that wait on Present by it, keeping the rate it started at as a floor unless the published one is at most 0.1% slower (59.94 under 60), so a vsynced application presents as fast as it is streamed; any other server holds it as inert data.

Statics§

VBLANK_RATE 🔒

Functions§

captured_damage 🔒
The share of the captured area at (x, y), width x height, that the root’s damaged rects cover.
clamp_offset 🔒
Clamp a capture offset to the live root so a grab always has at least one root pixel in range: a past-end offset fails every shm_get_image with BadMatch and would burn out the failure budget with no chance of recovery. The upper clamp also keeps protocol-range roots (INT16 coordinates) from truncating a wider value through the as i16 cast.
cursor_image_origin 🔒
Frame-space top-left of the cursor image, given the XFixes hotspot position.
encode_loop 🔒
Encode thread body: consume captured frames from the pool, keep the [pipeline::X11Pipeline] in step with the capture size and cross-thread controls, encode, recycle, and deliver.
follow_frame_rate
Republish VblankRate after a running capture’s frame rate changed.
frame_rects 🔒
The root’s damaged rects in the coordinates of the captured area at (x, y), width x height, clipped to it.
grab_frame 🔒
One shm_get_image request is atomic — the server never interleaves another client inside it — so the grab is a coherent snapshot of whatever the screen held at that instant. Every grabbed frame is published; whether any of it changed is decided downstream by the encoder’s own per-stripe damage detection.
open_framebuffer 🔒
The shared framebuffer of root’s screen (framebuffer), where the server offers one and its pixels over the capture region read as an XShm grab of it into surface does, or None, saying why where the server offers one that is not used. The comparison is tried a few times, since the screen may change between the grab and the read.
overlay_cursor 🔒
Composite the XFixes cursor (ARGB u32 per pixel, premultiplied by the XFixes format definition) onto the BGRA frame with its top-left at (img_x, img_y), blending each pixel through blend_pixel_premultiplied with per-pixel bounds clipping so an image straddling a frame edge writes only its in-frame portion.
readable 🔒
Wait for the connection to carry something, for at most timeout.
require_32bpp 🔒
Reject a server whose root visual is not 32 bits per pixel.
resolve_dims 🔒
Resolve the capture dimensions shm_get_image will read, bounded so the region can never run past the live root from the (clamped) capture offset: with auto-adjust (or unset width/height <= 0) the capture tracks the full root minus the offset, otherwise the requested size is clamped to what is available from it. Saturating subtraction plus a final u16 clamp (minimum 2) keep pathological settings from overflowing or collapsing to an unusable surface. Video codecs require even dimensions, so both are then rounded down to a multiple of two.
run_capture
Capture an X11 display until stop is set, on the best path this session can run.
run_shm_capture 🔒
Run the X11 capture pipeline until stop is set, splitting capture and encode across two threads that overlap for throughput.
take_tick 🔒
RootDamage::take for a tick trigger woke: whether the root changed since the last frame, and where. A report the take finds counts whatever woke the tick: one landing after the wait gave up is spent here all the same, and called clean, its change would be cleared with nothing left to report it (a capture that sends only changes would never send it).
try_rebuild_channel 🔒
Rebuild the X channel + capture surfaces after a connection-level failure (Xorg restart, VT switch), refreshing the offset/dims state against the live root. The pool is drained first so the encode thread can never be reading a surface as it is destroyed, and its generation is bumped so the encoder rebuilds against the new layout. Every fallible step completes before the swap, and the old channel/surfaces are destroyed best-effort after it (their server is likely gone; the local detaches still run, and the kernel frees each old segment once nothing maps it).
wait_for_frame 🔒
Block until the capture is due a frame and say what asked for it: a change the server reported, brought forward by as much as the pacing budget allows, or the frame timer.
wait_for_framebuffer 🔒
wait_for_frame on a shared framebuffer’s watch (framebuffer): a drawing operation the server signals on it ends the wait as a reported change would, with no round trip, and so does a resize retiring it.