Skip to main content

Crate pixelflux

Crate pixelflux 

Source
Expand description

§pixelflux

A high-performance screen capture and encoding pipeline: a Rust library, and with the python feature the pixelflux Python extension module built on it (python). It supports two independent backends — X11 (XShm + XFixes) and Wayland (a headless Smithay compositor) — and a shared encoding layer that dispatches to software (striped JPEG, H.264 through the build’s software encoder — libx264 with the gpl feature, OpenH264 without — and the other codecs through the software encoders the build links: x265 or kvazaar, libvpx, SVT-AV1) or hardware (NVENC, VA-API) encoders based on the available GPU and operator settings.

§Crate structure

ModulePurpose
encodersEncoder backends: software H.264 (libx264 or OpenH264) / JPEG, NVENC, VA-API, watermark overlay
waylandHeadless Smithay compositor, cursor rendering
x11X11/XShm capture loop, XFixes out-of-band cursor monitor, and stripe dispatch
pipelineFrame-processing policy shared by both backends (send/QP/keyframe decisions)
recording_sinkUnix-socket H.264 fan-out for external recording
recorderBuilt-in MP4 recorder (fMP4 muxer + API/env/REST control surfaces)
sinkWhat a capture hands its consumer, and the traits a consumer implements to receive it
pythonThe Python bridge, with the python feature: the classes and functions import pixelflux sees
computer_useAI-agent desktop control (screenshots, input injection, the recorder’s commands)
nvgpufilterMulti-GPU NVENC device filtering via ioctl
webcamVirtual camera: client webcam uplink decoded into a V4L2 device (interposer ring, v4l2loopback, PipeWire node)

§Data flow

Consumer  ──►  CaptureSettings  ──►  X11 / Wayland backend
                                        │
                                   frame pixels
                                        │
                                   ┌────┴────┐
                                   │ Encoder │  (NVENC / VAAPI / x264 or OpenH264 / JPEG)
                                   └────┬────┘
                                        │
                                  EncodedStripe(s)
                                        │
                                   FrameSink (a Rust consumer, or the Python callback)

Re-exports§

pub use error::Error;
pub use encoders::nvenc;
pub use encoders::software::StripeState;

Modules§

computer_use
The Anthropic Computer Use actions for AI agent desktop control. The Anthropic Computer Use actions on the captured desktop, and the recorder’s commands beside them, for whatever transport a host serves them over.
encoders
Encoder backends and the codec identities, wire framing, and rate-control policy they share. Encoder backends and what they share: the codec identities and wire framing, the rate-control policy, which software encoder a build resolves each codec to, and which hardware encoder a render node serves each with.
error
The one error type the public API returns. The one error type the public API returns. Each variant names the part of pixelflux that refused: the settings a consumer handed over, a capture, the compositor, or a capability the session lacks (a compositor without the virtual-keyboard protocol). The Python bridge maps them to its exceptions (ValueError for settings, VirtualKeyboardUnavailable for a missing capability, RuntimeError otherwise).
ledger
Per-block stillness and cleanliness of a region, for refining blocks while others move. Where a region’s picture stands, block by block: the per-block counterpart of the cleanup policy’s per-region bookkeeping (pipeline::cleanup_due).
log
The debug switch behind every backend’s tagged line. The verbosity switch behind every backend’s tagged line.
nvgpufilter
Multi-GPU NVENC device filtering via kernel ioctl. Multi-GPU NVENC GET_ATTACHED_IDS / GET_PROBED_IDS ioctl filter — it exists so a container handed only a subset of the host’s GPUs can still open an NVENC session.
pace
When a capture is due a frame, shared by the X11 and Wayland backends. The frame pacing every capture backend shares: when a display is due a frame, and how far a change that just happened may bring the next one forward.
pipeline
Frame-processing policy shared by the X11 and Wayland backends. Frame-processing policy shared by the two capture backends. It lives in its own module for one reason: the Wayland path (dmabuf, compositor damage) and the X11 path (host-ARGB, stripe-hash damage) capture pixels in completely different ways, but a viewer must never be able to tell which one produced a frame — a paint-over refresh or a recovery keyframe has to behave identically either way. Keeping the decision logic here, source-agnostic, is what guarantees it.
pipewire
Run-time libpipewire binding and SPA pod encoding shared by the webcam sink and host capture. Run-time binding to libpipewire-0.3 and the SPA pod encoding shared by every PipeWire user in pixelflux: the webcam sink (a Video/Source node) and the portal screen capture (a Video/Input stream). The library is loaded with dlopen, so pixelflux keeps no build-time or load-time dependency on PipeWire and each user simply stays off where the library or the daemon is absent. Pods are built and read by hand against the SPA wire layout: 8-byte aligned size, type, payload cells, objects carrying key, flags, cell properties, and a choice cell whose first value is the default (and, once fixated, the only) value.
recorder
Built-in MP4 recorder: independent capture-to-file with API/env/REST control. Built-in MP4 recorder: an independent pipeline that captures the desktop to a ready-to-play fragmented MP4 without needing any connected client.
recording_sink
Unix-socket H.264 recording fan-out for external capture tools. Unix-socket video fan-out for external recording.
report
What each capture streams and how it got there, as values a caller reads. What a capture streams and how it got there, for the caller to show its user: the capture path and whether it is zero-copy, the encoder and whether it is hardware, the GPU behind it, and the reason a faster path was declined. The same facts the tagged log lines state, kept as values so nobody has to read a log to learn them.
sink
What a capture hands its consumer, and the traits a consumer implements to receive it. What a capture hands its consumer, and the traits a consumer implements to receive it: the encoded frames of a capture ([FrameSink]), the pointer’s image as it changes ([CursorSink]), the clipboard a client application copies to ([ClipboardSink]), and the selection of an application compositor watched from outside ([SelectionWatch]).
uinput
Kernel uinput devices, the first rung of host-capture input injection. Kernel input devices for host-capture injection, over /dev/uinput.
wayland
Headless Wayland compositor and cursor rendering. Wayland backend: a headless Smithay compositor that stands in for a real display server.
webcam
Virtual camera: the browser’s webcam, delivered to applications as a V4L2 capture device.
wm
The window policy interface a window manager implements for the compositor. The window policy interface: what a window manager decides for the compositor.
x11
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.

Structs§

CaptureSettings
The full set of capture + encode parameters a consumer hands the backend.
CardIdentity 🔒
A DRM card’s identity as the kernel reports it, read from the device’s sysfs uevent (DRIVER=, PCI_ID=, OF_COMPATIBLE_n=) with per-file fallbacks (vendor, modalias, the driver symlink). uevent is uniform across buses (PCI, platform/devicetree, USB) and readable in unprivileged containers.
Compositor
The handle to the one long-lived compositor thread. Because calloop, EGL/GBM, and the Wayland display are all thread-affine and the compositor has to keep running to serve its clients even between captures, the backend cannot be a passive object that starts work on demand: constructing it spawns that thread and it stays up for the process lifetime. The struct itself is nothing but the command-channel sender used to drive that thread across the boundary; ensure_wayland_display hands out the process-wide one.
FrameScene 🔒
What an output’s frame is composed of, for composition_elements.
GpuBringUp 🔒
What the compositor renders with on a GPU, all of it brought up before any client hears of the GPU (gpu_bring_up).
LiveTunables
The per-frame decision/quality knobs every encoder re-reads from the settings on each tick, so they retune a running capture: x264, x265, and libvpx reconfigure, NVENC and VA-API retarget their constant quantizer, kvazaar and SVT-AV1 re-open, JPEG is stateless. A changed reference depth (video_reference_frames) re-opens an x264 session, on a key frame; a hardware session keeps the depth it opened with. Applied on the thread that owns the settings copy. Structural switches (encoder, chroma, RC mode, device) still need a capture restart.
ScState 🔒
Mutable per-capture state behind ScreenCapture’s mutex: the active backend, the live X11 controls and thread handle, and the capture / encode thread ids used to detect a re-entrant stop.
ScreenCapture
ScreenshotReadbacks 🔒
The persistently mapped pixel-pack buffers GLES screenshots are read back into, so the compositor only issues the transfer and the caller copies the pixels out once the GPU has written them. Without GL_EXT_buffer_storage, or with PIXELFLUX_SCREENSHOT_SYNC set, the compositor reads back synchronously into the caller’s buffer instead. Declared ahead of the renderer in AppState, so its drop forgets every mapping, waiting out a copy under way, before the GL context goes away.
SoftwareCursor 🔒
The software cursor an output’s frame draws, where it does: the theme that resolves a named cursor, what the client set, where the pointer is on the output, and the time for an animated cursor’s frame.
StreamInfo
Unified capture handle, the one a consumer holds. Drives the X11 capture directly or delegates to the shared Wayland backend, chosen at start_capture time. Exposes start_capture / stop_capture / request_idr_frame / update_* / is_capturing, plus the Wayland input-injection methods. What a capture streams and how it got there (ScreenCapture::stream_info): the report with the encoder’s GPU named, and the compositor’s renderer where the capture runs on Wayland.
StreamStats
A capture’s counters (ScreenCapture::stream_stats): the totals since it started and the extremes since the previous read.
WaylandGpuProbe
What probe_wayland_gpu found: the render node tried, whether it renders in hardware, the GL renderer’s name, and why it was refused where it was.
WaylandThreadConfig 🔒
Startup inputs for the compositor thread: its two calloop channels, the sender it hands to computer-use, the initial geometry, and the GPU / cursor policy.
WlEncodeConfig 🔒
Everything the Wayland encode thread needs, fixed for the life of one capture (a StartCapture reconfigure tears the thread down and spawns a fresh one). Rate changes flow through controls; damage and the IDR request arrive per-frame in WlFrame.
WlEncodeControls
Cross-thread controls for the Wayland encode thread, the X11 Controls scheme: the UpdateRate handler stores the current values then flips rate_dirty with Release; the encode thread swaps it with Acquire and re-reads the payload, never seeing it half-applied. force_idr is swapped just before each encode, so an on-demand keyframe lands on the frame ALREADY in flight instead of waiting one pipeline stage for the next publish. reference_reports are what clients said of frames (lost, or held by every one of them), drained ahead of the same encode.
WlEncodeStats
Shared capture stats: whichever thread owns the encoders counts frames/stripes and composes desc + n_stripes (the encoder half of the 1 s debug log line); the calloop log loads, prints, and resets the counters.
WlFrame
One captured frame in flight from the calloop (render/readback) to the Wayland encode thread: the slot’s buffer (a readback’s packed rows, or the zero-copy session’s GPU target) plus the per-frame inputs of the encode dispatch (damage, overlay animation); the IDR request travels separately via the controls atomic.
WlFramePool
Render->encode handoff for the Wayland readback paths, mirroring the X11 FramePool’s single-slot non-dropping design with one deliberate difference: the calloop thread is also the compositor + input dispatcher, so it must NEVER block on the pool. try_begin hands out a buffer only while the publish slot is empty, so publish cannot block, and a saturated encoder throttles capture by SKIPPING ticks (compositor damage accumulates via buffer age, so nothing is lost). Every published frame is encoded, in order: the H.264 reference chain stays contiguous exactly as on X11.
WlPoolInner 🔒
Interior state of WlFramePool: the free-buffer list plus the single publish slot.
ZeroCopySession 🔒
A zero-copy hardware session (GLES render + same-GPU dmabuf encode), driven by the capture’s encode thread. The calloop opens it and takes it back at a restart to reuse in place; the thread holds the lock for one encode at a time, never across a delivery.

Enums§

CompositionElements
ShotPixels 🔒
Where a screenshot’s pixels are once its output has rendered.
ThreadCommand
Control messages sent from the Compositor handle’s methods to the compositor thread.

Constants§

DEFAULT_FPS 🔒
DEFAULT_VIEW_ID 🔒
The view every screen carries from the start, covering it: the display a consumer gets without asking for a layout at all.
EGL_LIBRARY 🔒
The library smithay opens for its EGL calls, by the name it opens it by.
GEOMETRY_BARRIER_TIMEOUT 🔒
Bound on the geometry read-back barrier. Behind a host-capture start the read is held until the host has ruled on the requested mode, which the host’s control thread bounds by LAYOUT_DEADLINE, so this clears that with margin or a live-but-slow start would read as a timeout.
GL_CLIENT_STORAGE_BIT_EXT 🔒
GL_MAP_COHERENT_BIT_EXT 🔒
GL_MAP_PERSISTENT_BIT_EXT 🔒
GL_MAP_READ_BIT 🔒
HOST_MODE_REFUSALS_BEFORE_HINT 🔒
Refused mode requests in a row for one display before the log says plainly what to do: a host that keeps its own mode is asked again on every client resize, and each refusal restarts the capture at the mode the host runs.
HOST_QUIET_PERIODS 🔒
Periods without a fresh host frame before the timer treats the host as quiet and, in streaming mode, re-encodes the retained frame to hold the rate. A live host’s frames come about a period apart, so a tick landing a hair ahead of one must not publish a duplicate the fresh frame then waits behind.
HW_ERROR_RECOVERY_THRESHOLD 🔒
Consecutive encode failures before a hardware path recovers (~0.5s at 60fps): a hiccup outlasts it, anything longer starts to look like a dead session. Shared by every hardware encode path (Wayland zero-copy, Wayland readback, X11) so recovery timing matches.
IDLE_FRAME_INTERVAL 🔒
How often frame callbacks go out while nothing is being captured. Fast enough that a client blocked on one keeps making progress, slow enough that an unwatched session is not drawing frames nobody asked for.
MAX_CAPTURE_DIM 🔒
Upper bounds for consumer-supplied capture geometry: keeps a hostile or buggy setting from turning into a multi-GB vec![] allocation that would abort the process. 16384 covers every real display wall; the fps/scale bounds keep timing math finite and sane.
MAX_FPS 🔒
MAX_SCALE 🔒
OF_PREFIX_ALIASES 🔒
Human name -> devicetree vendor prefix, only where they differ (a token equal to the prefix itself, e.g. “qcom” or “rockchip”, matches directly).
READBACK_SLOTS_MAX 🔒
Pixel-pack buffers kept at once, as many screenshots as the process admits.
READBACK_SLOT_IDLE 🔒
How long an unused pixel-pack buffer is kept for the next screenshot.
RENDER_FENCE_TIMEOUT 🔒
Longest a render tick waits for the GPU to finish a frame before giving that frame up.
SCROLL_V120_PER_UNIT 🔒
Wheel v120 units per unit of injected scroll value: selkies sends 10 per notch, and one notch is 120, so both the seat’s v120 and the host virtual pointer’s discrete steps derive from the same value.
SHM_GONE 🔒
The error encode_shm_rows returns where the client’s pool no longer holds the frame.
STOP_JOIN_TIMEOUT 🔒
Best-effort nice boost for the calling capture/encode/delivery thread. These threads compete with the very workload being captured, so a scheduling edge keeps frame pacing steady under load. Requires CAP_SYS_NICE (or root); otherwise EPERM and silently a no-op. How long a stop waits for a capture or delivery thread to end before leaving it behind.
TRIGGER_FPS 🔒
The frame rate paint_over_trigger_frames is counted at.
UNDRAWN_TICKS_PER_FRAME 🔒
Render ticks in a row that draw nothing before one closes an empty frame on its target. smithay binds a dmabuf target through a texture with a framebuffer made for that bind, and the NVIDIA driver keeps the state of each one never drawn to until a frame retires it (a fence or a flush does not): about 15 KB a tick while the screen stands still.
VENDOR_PCI_IDS 🔒
Human vendor name -> PCI vendor IDs. The kernel has no such table (the grouping is conventional), and pci.ids/hwdata is often absent in containers, so this is the one mapping that must be embedded — kept to the names only.
VERSION
The crate version compiled in, for a host that names the pixelflux it links.
WL_CONTENT_HOLD 🔒
How long a reconfigured output holds its frames while its clients answer the new size. It is measured from the start, which rebuilds the encode path before there is any frame to hold: the first one arrives roughly 300 ms later, so a window shorter than that expires before it can suppress anything and the hold does nothing at all. This one outlasts the rebuild and a client’s own repaint, and is the whole delay an output that no client ever draws on pays before its content reaches the viewer regardless.
WL_POOL_SURFACES 🔒
Two buffers: one being encoded while the calloop fills the other. try_begin gates on the publish slot, so a deeper pool would only add latency (staler frames), never overlap.
WL_POOL_WAKE_QUANTUM 🔒
The encode thread’s bounded idle wait in WlFramePool::take.
XWAYLAND_VAR
The variable naming the Xwayland a caller ships, found ahead of the host’s (wayland::xwm::XWAYLAND_VAR).

Statics§

CURSOR_REGISTRATIONS 🔒
Every capture’s own cursor callback, the latest registration last: the process-wide slots carry the latest one’s, so a capture withdrawing its own (a second display leaving) hands the cursor back to the capture registered before it.
LIVE_X11 🔒
Registry of every live X11 capture’s Controls, so the atexit sweep can flag them all to stop before the interpreter finalizes even after the owning ScreenCapture Python handles have been dropped — without a central registry those captures would have no reachable stop switch.
NEXT_CAPTURE_ID 🔒
Hands each ScreenCapture a unique, monotonic id — the token WAYLAND_OWNERS compares to decide which instance is allowed to stop a display’s capture. Starts at 1 so 0 can mean “no owner”.
PENDING_CURSOR_CALLBACK 🔒
Cursor callback registered before the backend exists (selkies registers it pre-start); applied when the backend is created, which is deferred to capture start so the real render node (not a placeholder) reaches the compositor.
SHUTDOWN 🔒
Consumer-gone gate, set by shutdown: the detached compositor and delivery threads must never call a sink again, since the Python bridge runs shutdown from atexit and a sink attaching to a finalizing interpreter aborts the process (pre-3.13). Cleared by a fresh capture start (only a live consumer can start one).
WAYLAND_ACTIVE_CODEC 🔒
Record (or clear, with None) the last-start outcome for display_id.
WAYLAND_ALIVE_DISPLAYS 🔒
Display ids whose capture pipeline is actually running (StartCapture inserts, StopCapture/DestroyOutput remove), so the Python-facing is_capturing() reports pipeline liveness, not merely which ScreenCapture owns the backend.
WAYLAND_BACKEND 🔒
Process-wide Wayland backend: input and capture share ONE compositor (constructed lazily).
WAYLAND_CAPTURE_ERR 🔒
Per-display outcome of the most recent capture start, recorded by the calloop thread so the Python-facing capture_state can report it. A start that came up clean removes its entry; a hard failure (no output, …) or a caveat that still capturing (host connect failed -> local compositing, hardware encoder fell back to CPU) leaves the reason here. Distinct from wayland_alive, which says only whether the pipeline runs.
WAYLAND_OWNERS 🔒
Per-display capture ownership: display id -> the ScreenCapture id that owns that display’s capture. Only the owner may stop it, so an input-only or stale instance can’t tear down a live capture.
WAYLAND_SOCKET_CV 🔒
WAYLAND_SOCKET_NAME 🔒
The compositor’s auto-picked socket name (e.g. “wayland-1”), published by the compositor thread once its listening socket exists. ListeningSocketSource::new_auto binds the first FREE wayland-N, which need not match any configured index — consumers must read the real name from here instead of assuming one.

Traits§

WlPayload 🔒
What a Wayland encode thread encodes a frame from: the packed rows a readback filled, or the GPU buffer a zero-copy session encodes in place.

Functions§

alloc_render_target 🔒
The buffer a display is rendered into and a hardware encoder reads in place: one plane, for rendering. Intel’s video processor, converting to 4:2:0, reads a linear surface at a pitch rounded up to 64 bytes whatever pitch its import declares, and Mesa gives a linear buffer allocated for rendering alone the pitch of its width, so a width that is no multiple of 16 reaches the encoder sheared. A buffer the display engine may scan out carries that engine’s aligned pitch, so a linear allocation whose pitch is not a multiple of 64 is made again for scanout as well, and that one is kept only where it came out aligned.
alloc_zero_copy_ring 🔒
WL_POOL_SURFACES zero-copy render targets the size of the capture, or None where the GPU refuses one.
announce_scale_to_windows 🔒
Tell every window on an output the output’s scale: the surface’s preferred buffer scale and fractional scale, so a client draws at the new density rather than being stretched to it. The size a client keeps is the policy’s business where one runs, and the fullscreen configure’s otherwise.
answer_frame_callbacks 🔒
Answer the frame callbacks of each captured display’s clients once a window, on its boundary: the vblank a display gives them. A change renders as it lands (serve_changes), and a client drawing on frame callbacks takes its clock from them, which the boundaries keep even. The frame timer wakes at every boundary while a display captures, and calls this each time.
answer_geometry_waiters 🔒
Answer geometry readers parked behind a host layout request with what display_id captures now.
app_socket_path 🔒
The pixelflux Python module: registers the exported classes and functions, and hooks _stop_all_captures into atexit so every live capture is stopped before interpreter shutdown. Socket path for a Wayland display name, with the ABI methods’ error shape.
auto_render_node 🔒
The render node an auto_gpu request picks: None where the request is off or matches no node.
auto_select_render_node 🔒
Resolve a usable /dev/dri/renderD* node, optionally matching a vendor/driver token.
boost_thread_priority 🔒
Give the calling thread the nice level nice, below the default. setpriority takes it only with CAP_SYS_NICE or an RLIMIT_NICE that reaches it, which a session’s process rarely has; where it refuses, the request goes to rtkit over the system bus, which grants a level within the daemon’s own bounds to any process of the seat. A host without rtkit, or without a system bus at all as a container is, leaves the thread at the default, said once in the log.
bootstrap_readback_pool 🔒
Start (or in-place reconfigure) the capture bound to output display_id: reprogram the output’s mode/scale/refresh, size the render targets, fullscreen the display’s windows at the new logical size, resolve the encode path (zero-copy vs readback), and spawn the delivery (and readback-mode encode) threads. The single-display behavior of the former global StartCapture is preserved exactly for display 0. Bring up the readback encode path (pixman readback → pool → encode thread) for a capture whose zero-copy session is absent or just died. Mirrors the start-capture bootstrap: u64::MAX content generations mark every pool slot stale so each one is read back before its first publish, whatever the damage says.
bootstrap_zero_copy_pool 🔒
Start a zero-copy capture’s encode thread on encoder, a session the calloop opened on the renderer’s EGL display, on ring’s render targets.
build_readback_encoders 🔒
Build the readback-mode frame encoder on the thread that will own and drive it: the shared ladder with host frames (rgba for a GLES readback, BGRA otherwise), with the GPU rungs skipped when try_gpu is off (the recovery ladder’s demotion). None is the CPU path, where encode_cpu builds its own per-region state. A compatible NVENC session handed over from the previous encode thread is reconfigured in place rather than rebuilt, which would stall the stream.
cancel_slots 🔒
Hand back the pool reservations a render tick made and did not publish.
capture_period 🔒
The frame period a capture renders at.
card_matches_token 🔒
Does a card match the requested token? Accepted token forms, checked against the identity the kernel itself reports: a kernel DRIVER name (exact, no table), a raw PCI vendor ID (“0x10de”/“10de”), a devicetree vendor prefix (literal first segment of any compatible), or a human vendor name resolved through the small embedded alias maps above.
compose_host_frame 🔒
Re-compose src (the retained host frame) into target, with the watermark where overlay is given: the path a moving watermark needs, since re-drawing over the same retained buffer would leave trails.
composited_target 🔒
The GPU target the last render composited into: source, a zero-copy capture’s target still on the calloop, or else the output’s own.
composition_elements 🔒
The render elements of an output’s frame, topmost first: the software cursor, a drag’s icon, the watermark, the window manager’s overlays, the overlay and top wlr-layer layers, the windows with their frames, and the bottom and background layers. One list for both renderers, read by scanout_candidate before anything is drawn.
configure_windows_for_mode 🔒
copy_rows_into_shm 🔒
Copy full rows from src (tight width*4 stride) into an Argb8888/Xrgb8888 shm buffer, honoring the destination’s own offset and stride.
create_dmabuf_from_bo 🔒
Export the offscreen GBM render target as a Dmabuf so the very same GPU pixels can be both rendered into and encoded with no intervening copy — the linchpin of the zero-copy capture path. The returned dmabuf is the one handle the GLES renderer binds as its framebuffer AND a hardware encoder (NVENC through CUDA, or VAAPI) imports to read those pixels directly, which only works if the buffer is described precisely enough (fd, stride, DRM modifier) for the importer to interpret it. The render targets and host capture slots have one plane; retain the BO’s format so an opaque host slot is not imported as a buffer with alpha.
create_output_on 🔒
Create an additional output mapped into the layout at (x, y). Fails (false) on a duplicate id, non-positive geometry/scale, a rectangle overlapping a live output, or a GPU render-target allocation failure. Only Create/Reposition placements are validated: a capture reconfigure (StartCapture on an existing output) resizes UNVALIDATED, so keeping a multi-step relayout overlap-free at every step is the caller’s ordering responsibility.
create_view_on 🔒
Add a view: a display over a rectangle of owner’s output.
cursor_surface_hotspot 🔒
Hotspot of a surface-backed cursor, in the surface’s logical coordinates (zero when the client set none). The sprite is placed at pointer - hotspot, like named and X11 cursors.
desktop_view
The desktop as the window policy installed on the running compositor holds it; None where no compositor runs or none has a policy.
destroy_output_on 🔒
Destroy a secondary output: end its capture, relocate its windows onto the primary output, unmap it from the space, and retract its global. The primary (id 0) is refused.
detach_retained_gpu 🔒
HostSession::detach_retained for a GPU frame, which only a zero-copy session takes: the renderer copies it into a buffer of the capture’s own, which re-encodes then read, and the stream’s buffer goes back once no frame in flight reads it.
draw_host_watermark 🔒
One output’s render + capture tick: composite the elements overlapping this output (positions made output-local by subtracting its layout origin), track damage, feed the display’s own encode path, and answer a pending screenshot on the primary. Returns true when the tick was skipped because this display’s encode pool was still busy (the caller then retries shortly instead of waiting a full frame interval). Stamp the watermark element onto target in place — no clear, so the captured content underneath stays — returning the draw’s sync point for the encoder to wait on.
driver_selects_nvenc 🔒
Whether an encode node’s driver name routes to NVENC: NVIDIA, or unknown (no readable render-node sysfs entry, the usual shape of an NVIDIA container without /dev/dri), so the NVENC attempt runs before the CPU fallback. Any other named driver routes to VA-API. Shared by the X11 and Wayland paths so both pick the same encoder for the same node.
drives_screen 🔒
Views share one output, so its clients are driven once a frame, by the fastest display capturing that screen (ties go to the lowest number) – a client asked to draw once per view would render as many times a frame as there are displays over it, one asked by nobody (the screen itself is often captured by views alone) would freeze on the frame it first painted, and one driven by a slower sibling would stream stale frames on the faster display.
egl_display 🔒
An EGL display on native, or an error where libEGL is not installed.
egl_library 🔒
Whether EGL_LIBRARY opens. It is opened once and kept open, so smithay’s own open of it finds it loaded.
encode_shm_rows 🔒
Run encode on the rows of a client’s shm buffer a frame names (WlFrame::shm), height rows of width pixels packed four bytes each: the pool’s mapping is valid only inside this call, so the encode runs inside it. SHM_GONE where the pool was resized or destroyed under the frame.
encoder_desc 🔒
Compose the encoder half of the 1 s debug log line (backend, colorspace, rate control) for whichever thread owns the encoders.
end_zero_copy 🔒
Stop a capture’s zero-copy session: its encode thread ends after the frame in flight, and its render targets go. False where none ran.
ensure_compositor
Get-or-create the singleton Wayland backend (idempotent: the first dimensions and render node win, and a later capture just resizes).
ensure_wayland_display
Bring up the process-wide compositor (ensure_compositor) and return its socket name, so a consumer can place WAYLAND_DISPLAY for the clients it starts; empty where the compositor published no socket within five seconds.
find_output_overlap 🔒
The first live screen (excluding skip_id; views stand behind their owner’s rectangle) whose rectangle overlaps a candidate placement. Both rectangle flavors are checked — logical (Space layout, scale-divided) and physical (mode pixels at the same origin) — because input injection and cursor compositing key off the physical rects while window layout keys off the logical ones, and neither may overlap.
first_render_node_index 🔒
The index of the first render node present, which a capture that names none encodes on: renderD128 need not exist, as in a container handed one GPU of several.
frame_period 🔒
The frame period for a target rate. Settings are sanitized at the API boundary; a rate outside the sane range takes the default here so a non-finite one never reaches Duration::from_secs_f64.
get_gpu_driver 🔒
Read the kernel driver bound to a render node for encoder routing.
get_process_rss_bytes 🔒
get_shm_usage_bytes 🔒
gl_renderer_name 🔒
GL_RENDERER of a live renderer — the driver that actually answered, which is the only thing that separates a GPU from Mesa’s software fallback on the same node. Empty when the context cannot be made current or the string is unavailable.
gpu_bring_up 🔒
The GL renderer on device_path, the dmabuf formats it imports, and its offscreen render target at width by height. It touches no Wayland global: the caller advertises the GPU only once this succeeded, since a dmabuf global left behind by a failed start (a render node whose EGL comes up but whose allocator refuses the target, as on a virtual GPU) offered the GL renderer’s formats to a compositor rendering in Pixman, which refused every buffer, and a nested kwin_wayland died of the protocol error.
gpu_exposed 🔒
A GPU is exposed to this container or machine.
gpu_render_init 🔒
Bring the hardware renderer up on a DRM render node: the GBM device, the EGL display and context it backs, the GLES renderer, and the allocator the render targets come from.
hardware_encoders
The hardware encoders of the encode node encode_node_index names (-1 for none, below -1 for the auto_gpu pick or the first render node), by codec: the backend’s name and the formats it codes the codec in.
host_layout_resolution 🔒
What the mode a host announced means for a capture configured at want, once the host has ruled on the layout request: Some(size) when the capture must follow a different mode the host runs, None when nothing changes — the host runs the requested size, or its mode is unknown and the capture keeps gating on the size it asked for. The verdict itself is not consulted: a host may answer succeeded for a mode it did not take (Hyprland acknowledges a custom mode it rejected), so the announced size decides. It has arrived by the time any verdict does, both riding the one host connection in order.
install_window_policy
Install a window policy on the running compositor; an error where none runs.
join_within 🔒
Join handle if it ends within STOP_JOIN_TIMEOUT, else leave the thread behind with one line saying so: a thread held inside a driver call that never returns must not hold the stop, and with it every later capture of the session, with nothing said.
live_x11 🔒
log_stream_settings 🔒
One-shot “Stream settings active” line, printed by the thread that owns the encoders once the selection is final (calloop for zero-copy, encode thread for readback, the X11 zero-copy backends at their start), tagged for the backend that prints it.
log_stream_settings_of 🔒
The “Stream settings active” line for a backend named outright, (name, hardware), where the session is not a FrameEncoder (NvFBC’s own NVENC session); None is the CPU path, fixed_rate is the backend’s one rate control where it has one (FrameEncoder::fixed_rate_control), holds says whether the session holds a cleanup at the quantizer asked for (FrameEncoder::holds_quantizer), and capped whether a constant quality runs under the peak of video_bitrate_kbps (encoders::session_capped).
memfd_create 🔒
memfd_create(2) through the raw system call: glibc wraps it only from 2.27, and the wheels hold to the glibc 2.17 manylinux floor. The descriptor, or -1 with errno set.
node_gpu_name 🔒
The name the GL driver gives the GPU behind render node node_index, asked once per node and remembered: what a VA-API session, which names no device, is reported to run on. Empty where no GL context comes up on the node.
note_direct 🔒
Say, at debug, that a display’s frames moved between compositing and a client’s buffer, or are composited for a new reason: the choice is made every frame, so only its change is worth a line.
parse_auto_gpu 🔒
Parse an auto-GPU request (the CaptureSettings auto_gpu field, which selkies fills from –auto-gpu / SELKIES_AUTO_GPU). None = disabled; Some(None) = pick the first GPU overall (“true”); Some(Some(token)) = pick the first GPU whose kernel identity matches the case-insensitive token (vendor name, kernel driver name, devicetree vendor prefix, or raw PCI vendor id).
probe_wayland_gpu
Probe the render node the compositor would run on: render_node explicitly, else the auto_gpu pick. Allocates one GBM buffer, exports it, and opens a GL context on it, so a deployment learns before starting whether the compositor renders in hardware.
publish_socket_name 🔒
push_ghost_elements 🔒
Push the ghosts of closing windows the policy animates, over the windows: each its last picture and frame scaled and blended through its effect.
push_layer_elements 🔒
Push an output’s wlr-layer surfaces on target_layer into elements, top-most first, the order layer_map.layers() reversed gives, each with its popups and subsurfaces. Shared by both renderers and by both of a frame’s layer passes, which differ only in the layers they name.
push_window_elements 🔒
Push a window’s elements for an output at origin and scale: through the window policy’s effect where one runs on it (the surface tree scaled into the effect’s rectangle and blended at its alpha, the frame parts scaled and blended with it), else as the window stands with its frame parts beside it.
read_back_rgba 🔒
Reads target back as RGBA into dst. The read runs in a frame of the target: a dmabuf bound as a texture gets a framebuffer of its own on each bind, which only a frame makes current, so a bare read on a tick that drew nothing would read another framebuffer.
read_back_rgba_async 🔒
Start reading the bound target back into a pixel-pack buffer and return the readback the caller waits for, or None where the buffers are unavailable.
read_back_rgba_result 🔒
Screenshot reads also check GL errors before any pixels can be handed to the caller.
read_card_identity 🔒
Read a DRM card’s CardIdentity from sysfs.
realized_geometry 🔒
The geometry get_realized_geometry reports for display_id: the live capture’s size and scale, else the output’s current mode, else zeros for an unknown display.
reap_dead_host 🔒
Drop a host-capture session whose compositor connection has ended, stopping every capture it fed: their displays leave the alive set, so is_capturing turns false and the consumer rebuilds them (the next start reconnects), and no input is written to a dead connection. The same signal X11 gives when its capture thread ends.
reconcile_host_layouts 🔒
Settle the host layout requests answered since the last tick, against the mode each host announced. A host already running the requested size needs nothing: the capture was configured for it and its frames flow. A host running anything else — a request it refused, acknowledged without applying, or never answered by the deadline, and a host with no layout management at all — has the capture re-sized to that mode through the same in-place reconfigure a resize takes, so it never gates on a size the host will not produce, and the mismatch becomes the capture’s caveat. Geometry readers parked behind a request answer once it is settled, with the size actually captured.
recording_status
The recording in progress or last finished, None where none was started.
rects_overlap 🔒
True when the rectangles (x, y, w, h) overlap: strict interior intersection, so touching edges do not count and empty (non-positive-dimension) rectangles never overlap anything. Arithmetic is widened so extreme coordinates cannot wrap.
release_host_inflight 🔒
Hand back to the host the frames its compositor blitted that a zero-copy encode no longer reads: each once the encode thread is done with every frame published from it, or all of them (all) where the capture is going away.
release_scanout_inflight 🔒
Let go of the client buffers encoded as they stood that no frame in flight reads anymore (WlCapture::scanout_inflight), or all of them (all) where the capture or its zero-copy session is going away: the last hold on one releases it to its client.
render_display 🔒
One display’s render tick, for a trigger that concerns that display alone.
render_node_index 🔒
The index encode_node_index counts a render node path by (/dev/dri/renderD{128 + idx}).
render_node_tick 🔒
One display’s frame: decide whether this tick produces one, reserve a pool buffer, take the host’s frame or compose the output’s own, publish it to the encode thread, and answer the clients’ frame callbacks and presentation feedback. True where the encoder still holds every pool buffer and the tick is skipped.
render_pass 🔒
Render every output that is due for trigger, and say whether a readback pool was still busy. The nodes are taken out of the state so each per-output render can borrow the shared renderer/space alongside its own damage tracker and buffers.
reposition_output_on 🔒
Move an existing output (the primary included) to layout offset (x, y). The output’s advertised position, its Space mapping, and the windows placed on it (mapped at the output’s origin — window positions are output-relative under forced fullscreen) all follow, so absolute input injection and cursor compositing — both keyed off node.pos — resolve against the new layout immediately. A destination overlapping another live output is refused (false). As with CreateOutput, only the placement itself is validated: a capture reconfigure (StartCapture on an existing output) resizes UNVALIDATED, so keeping a multi-step relayout overlap-free at every step is the caller’s ordering responsibility.
resize_output_on 🔒
retain_host_frame 🔒
Keep frame as the display’s host content. Under a zero-copy session the frame it replaces goes back to the host only once no frame in flight to the encode thread reads it.
run_wayland_thread 🔒
The main execution loop of the Wayland backend.
running_compositor
The live Wayland backend, if any — never creates one. The pre-capture entry points (input injection, cursor/config setters) use this so they can’t lock in a backend with a placeholder render node.
scanout_candidate 🔒
The surface whose buffer is an output’s frame as it stands, or why there is none.
scanout_dmabuf 🔒
A client’s dmabuf the zero-copy session encodes as it stands, with its description for the log, and a hold on the buffer, or why the session cannot take it: both hardware sessions import one of the four packed 8-bit RGB formats at their own width and height, so only a buffer of the capture’s size qualifies, and of no more planes than the session’s encoder imports (planes: VA-API maps a compressed layout’s metadata plane, NVENC one plane). What the driver then makes of its modifier and pitch only the import says, and a refusal there ends the direct path for the capture (WlEncodeControls::scanout_refused).
scanout_shm 🔒
A client’s shm buffer the readback path encodes where it lies, with its description for the log, or why not: the rows have to be what the pool’s are, B,G,R,A (ARGB8888 or XRGB8888) packed at the capture’s width, since the encoders read them at that pitch.
screenshot_len 🔒
The byte length of one width x height RGBA frame, None for an empty or overflowing one.
screenshot_pixels 🔒
Copy exactly one complete frame into a caller’s buffer, excluding any scratch-buffer capacity from an older size.
screenshot_png
A PNG of display display as the capture backend sees it now.
send_cursor_frame 🔒
Answer the frame callbacks of a surface-backed cursor. Xwayland and libwayland-cursor clients wait for the cursor surface’s frame callback before attaching their next sprite, so a cursor surface that never gets one stops updating after its first sprite.
serve_changes 🔒
Render each capture a change waits on (WlCapture::change_pending: a client’s commit, input, a host frame) once its period is open: a change takes its period’s frame as it lands, the X11 captures’ schedule, rather than waiting for the frame timer. A capture whose period a frame already took keeps waiting, and the timer wakes as the next one opens.
service_copy_frames 🔒
Complete parked ext-image-copy-capture frames for this output from the frame the render pass just produced. A dmabuf target is filled by one GPU blit from the composited buffer (composited_target); an shm target by one readback (GLES) or one row copy (pixman). With no damage, a session that has already received content keeps its frame parked, so a static screen costs capture clients nothing.
set_wayland_active_codec 🔒
set_wayland_capture_err 🔒
shm_usage_in 🔒
Blocks actually allocated, not apparent size, so a sparse file is not reported as memory the process took. Feeds the debug log line only.
shutdown
Stop every live capture ahead of the process’s exit, and raise the consumer-gone gate first so no detached thread calls a sink again.
start_capture_on_display 🔒
start_recording
Start the built-in MP4 recorder on path: with settings, a recorder-owned H.264 capture of the display and backend they name (any other codec is refused); without, the capture the PIXELFLUX_RECORD_* environment describes. audio_socket names pcmflux’s recording socket, empty for none.
start_xwayland
Start Xwayland on the running compositor; notify is told the display number.
stop_capture_on_display 🔒
Stop the capture bound to display_id, leaving the output (and every other display’s capture) running.
stop_recording
Finalize the recording in progress and report what it wrote.
stream_settings_line 🔒
The text of the “Stream settings active” line, which says what the session applies rather than what it was asked for (encoders::rate_desc, encoders::paint_over_desc).
teardown_capture 🔒
Tear down a capture’s encode/delivery threads and pools, returning both join handles as (deliver, encode) for the caller to place. NEITHER is joined here: this runs on the calloop thread, which also dispatches Wayland clients and input, and either thread can be parked behind a consumer still inside Python. A restart hands each handle to its successor thread, which joins it off the event loop — the encode successor inheriting the readback hardware session, the deliver successor keeping stripes in capture order across the restart — and a plain stop hands both to the reaper. The zero-copy session (if any) is left on the capture for the caller to reuse or drop, and so are the host frames its thread may still be reading (release_host_inflight).
unpremultiply_rgba 🔒
Convert premultiplied-alpha RGBA pixels to the straight alpha PNG expects. Every cursor source feeding the callback stores premultiplied color (XFixes and Xcursor by format definition, wl_shm/dmabuf by Wayland convention); encoding those values as straight alpha double-darkens antialiased edges. Rounds as (c * 255 + a/2) / a, clamped — selkies’ python seed path mirrors this exact integer math so both sources hash a cursor to the same content handle.
validate_host_screenshot 🔒
Reject truncated host mappings instead of retaining pixels from an earlier frame.
wait_render_fence 🔒
Wait, bounded, for a render’s fence to signal before the tick reuses or releases the buffers it sampled.
wait_socket_name 🔒
Wait (bounded) for the compositor thread to publish its socket name.
warn_once_host_watermark 🔒
wayland_active_codec 🔒
The codec each Wayland display’s capture streams, as Codec::id, read by ScreenCapture::active_codec without a round trip to the compositor thread.
wayland_alive 🔒
wayland_capture_err 🔒
wayland_capture_state 🔒
(state, last_error) for display_id’s Wayland capture, from the shared liveness and outcome maps (no command round-trip).
wayland_display_name
The socket name of the running compositor, None without one or where it published none within two seconds.
wayland_encode_loop 🔒
Encode-thread body for the Wayland captures: drain published frames and run the full encode dispatch, driving the encoders for the life of the capture.
wayland_owners 🔒
wayland_update_link_rate 🔒
Forward the rate a display’s path carries to the shared Wayland backend (no-op if none is running).
wayland_update_rate 🔒
Forward a live rate change to the shared Wayland backend (no-op if none is running).
wayland_update_tunables 🔒
Forward live per-frame tunables to the shared Wayland backend (no-op if none is running).
window_request
Ask the window policy installed on the running compositor to act on a window; false where no compositor runs or none has a policy.
windows_on_display 🔒
Resize a screen’s output, keeping its position, so the displays cut out of it can be laid out over a different desk.

Type Aliases§

BufferStorageFn 🔒
glBufferStorageEXT, which GLES has only through GL_EXT_buffer_storage.
OutputDesc
One live output as (id, x, y, width, height, scale, capturing). Sizes are physical pixels and (x, y) is the layout offset.
OutputOverlap 🔒
An overlapping output as (id, flavor, rect), where flavor names which rectangle pair matched and rect is (x, y, width, height).
WindowDesc
One mapped window as (window_id, title, app_id, output_id, parked). A parked window has no output yet — a nested session’s spare screens.