Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions docs/selkies/components/baseimages.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ There is deliberately **no `latest` tag** for base images. Downstream images pin
- **The LSIO foundation**: each tag builds on the corresponding LinuxServer.io distro baseimage, inheriting s6-overlay init, the `abc` user with PUID and PGID remapping, `TZ`, Docker mods, and the `/custom-cont-init.d` and `/custom-services.d` hooks.
- **Selkies** (pinned commit) installed into the `/lsiopy` virtualenv, with pixelflux 2.x and pcmflux 2.x, plus [Pelorus](pelorus.md) preinstalled.
- **The web client**: prebuilt dashboards under `/usr/share/selkies/`, selected at runtime by the `DASHBOARD` variable.
- **Compositors for both stacks**: labwc (built from source with a small IPC patch that adds the window query socket Pelorus uses) for Wayland, and a patched Xvfb (with `-vfbdevice` DRI3 support) plus Openbox for the legacy X11 fallback. A patched wlroots build makes the compositor survive pixman rendering faults instead of crashing.
- **Display servers for both stacks**: labwc (built from source with a small IPC patch that adds the window query socket Pelorus uses) for Wayland, and an XLibre Xvfb built with glamor and DRI3 plus Openbox for X11. The Xvfb carries a LinuxServer patch that keeps the screen pixmap on the GPU and lets the framebuffer follow RandR resizes, which is what makes zero copy capture possible on X11. Both are prebuilt per distro in [selkies-layers](https://github.com/linuxserver/selkies-layers) and copied into the image. A patched wlroots build makes the compositor survive pixman rendering faults instead of crashing.
- **[Selkies Desktop](selkies-desktop.md)** at `/usr/bin/selkies-desktop`, activated by env var.
- **Nginx** with the fancyindex module, serving the client, proxying the WebSocket, handling basic auth, subfolder support, and the `/files` download index.
- **PulseAudio** with null sinks (`output` and `input`) wired for stream audio and microphone return.
- **Gamepad plumbing**: the joystick interposer and fake udev libraries, preloaded globally, with device nodes created at init.
- **Gamepad plumbing**: the input interposer and fake udev libraries, preloaded globally, with device nodes created at init.
- **Quality of life**: passwordless sudo for the desktop user, all system locales prebuilt for `LC_ALL`, `proot-apps` synced into the user home for persistent app installs, Docker in Docker support for privileged containers, and notification support.

## The runtime in one diagram
Expand All @@ -47,15 +47,17 @@ graph TD
SELKIES -->|starts in process| PF[pixelflux Wayland compositor, socket wayland-1]
DE -->|waits for wayland-1| LABWC[labwc or a full DE, exposes wayland-0]
LABWC --> APP[autostart application]
NGINX -->|3000 / 3001| WEB[web client, /websocket proxy, /files, /pelorus]
NGINX -->|3000 / 3001| WEB[web client, /api proxy, /pelorus]
```

At startup a chain of one shot init scripts configures everything from environment variables: Nginx substitution (ports, auth, subfolder, title), Wayland or X11 mode selection, first run copy of the autostart and menu defaults into `/config`, hardening (the `HARDEN_*` and `DISABLE_*` family), GPU detection and permission fixes, and gamepad device setup. Then the long running services above come up in dependency order.

## The two session modes

- **Wayland (default on capable hardware)**: pixelflux hosts the virtual compositor; labwc (single apps) or a full desktop (Webtop flavors) nests on it; zero copy GPU encoding is available. `PIXELFLUX_WAYLAND=true` is baked into current downstream images.
- **X11 (legacy fallback)**: patched Xvfb with DRI3, Openbox, XSHM capture. Selected with `PIXELFLUX_WAYLAND=false` or on flavors that have not moved to Wayland yet. Deprecated for GPU work.
- **Wayland**: pixelflux hosts the virtual compositor; labwc (single apps) or a full desktop (Webtop flavors) nests on it. `PIXELFLUX_WAYLAND=true` is baked into images whose application or desktop runs on Wayland.
- **X11**: XLibre Xvfb with glamor and DRI3 on `:1`, Openbox for single apps or the desktop's own window manager, and pixelflux capturing the GPU resident screen through DRI3. Selected with `PIXELFLUX_WAYLAND=false`, and the stack for applications and desktops that run best on X11.

Both stacks encode with zero copy on a GPU and share the same CPU encoders without one.

## The downstream contract

Expand Down
4 changes: 2 additions & 2 deletions docs/selkies/components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ graph TD

To make the layering concrete, here is the life of one frame in a Wayland mode container:

1. The application renders into a buffer belonging to **labwc** (or KWin on KDE), which is itself a client of the headless Smithay compositor that **pixelflux** hosts in process.
2. Pixelflux composites the output. If a GPU holds the framebuffer and the encoder lives on the same GPU, the frame is passed as a DMA-BUF straight into NVENC or VA-API, zero copy. Otherwise it is read back and encoded on CPU, in parallel stripes if the software encoder is in use.
1. The application renders into a buffer belonging to **labwc** (or KWin on KDE), which is itself a client of the headless Smithay compositor that **pixelflux** hosts in process. On X11 the application instead draws into an XLibre Xvfb whose screen pixmap lives on the GPU, and pixelflux blits it out through DRI3 rather than compositing it.
2. Pixelflux composites the output. If a GPU holds the framebuffer and the encoder lives on the same GPU, the frame is passed as a DMA-BUF straight into NVENC or VA-API, zero copy, for any codec the card carries. Otherwise it is read back and encoded on CPU, in parallel stripes for H.264 and JPEG and full frame for the other codecs.
3. Only regions that changed get encoded at all; a static screen costs almost nothing, and after motion stops a high quality paint over pass restores perfect detail.
4. The encoded frame, with a small binary header, is handed to **Selkies**, which broadcasts it over the WebSocket to every connected viewer with backpressure control per client.
5. The container's **Nginx** carries that WebSocket alongside the static web client, file downloads, basic auth, and the optional Pelorus API, all on one HTTPS port.
Expand Down
Loading
Loading