forked from unom/punktfunk
feat(gamescope/hdr): HDR is attempted by default and every install path ships the patched gamescope
Field report (RX 5700 / SteamOS): 10-bit HEVC "unsupported" — but the GPU was
never the blocker (RADV probed Main10 fine on that box). The session stayed SDR
because stock gamescope offers no 10-bit PQ capture formats and nothing shipped
our pipewire-hdr build outside the Bazzite sysext, while PUNKTFUNK_GAMESCOPE_HDR
additionally defaulted off everywhere. Close all three gaps:
- PUNKTFUNK_GAMESCOPE_HDR now defaults ON (explicit-off grammar, the flip the
config comment planned post-canary). Safe by construction: the +pfhdr banner
probe, managed-spawn term, and client 10-bit cap keep stock-gamescope boxes on
the exact 8-bit path. The nix module's gamescopeHdr (default true now) only
controls whether the patched binary is on PATH; it no longer sets the env.
- SteamOS: new scripts/steamdeck/build-gamescope.sh builds the HDR gamescope in
the same pf2 trixie distrobox (apt dep list validated by a full build in a
debian:trixie container), installs ~/.local/bin/punktfunk-gamescope, and
maintains PUNKTFUNK_GAMESCOPE_BIN in host.env ONLY while the binary passes its
on-glass --version/+pfhdr check — a stale absolute override would break
session spawning, not just HDR. Wired into install.sh (§3b), update.sh
(retrofit), and rebuild-check.sh (ldd-probes it like the host binary).
- Arch: build-sysext.sh gains a --gamescope fold-in (banner-verified by
execution, host-image-only), and punktfunk-host optdepends the companion.
Deliberately NO CI-published host sysext: per the 2026-07-22 packaging
verdict a prebuilt SteamOS host breaks on A/B soname bumps (and /var is
per-partition-set), so arch.yml records that instead — SteamOS hosts use the
distrobox flow above.
Also fixes a latent bug that made build-sysext.sh fail every invocation as
documented: a literal `}` inside `${1:?usage …{host,client}…}` terminates the
expansion early and corrupts $PKG (caught by the new synthetic-package test,
which also covers the fold-in, the unmarked-gamescope refusal, and the
client-image guard).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -210,6 +210,13 @@ jobs:
|
||||
rm -rf dist-gamescope # never cache a failed build (an empty path is not saved)
|
||||
fi
|
||||
|
||||
# NOTE deliberately NO sysext image is built or published here: a prebuilt HOST binary on
|
||||
# SteamOS breaks on the next A/B soname bump (and /var — where sysexts live — is
|
||||
# per-partition-set), which is the standing packaging verdict behind the on-device
|
||||
# distrobox build (scripts/steamdeck/, see scripts/steamdeck/README.md). That flow builds
|
||||
# its own HDR gamescope too. packaging/arch/build-sysext.sh remains a by-hand tool for the
|
||||
# Deck CLIENT image and for operators who accept the prebuilt-host trade-off.
|
||||
|
||||
- name: Publish to the Gitea Arch registry
|
||||
env:
|
||||
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
@@ -151,10 +151,12 @@ pub struct HostConfig {
|
||||
/// gamescope's PipeWire node the 10-bit PQ capture formats; the host probes for it and stays
|
||||
/// SDR when it isn't installed, so this knob only decides whether HDR is *attempted*.
|
||||
///
|
||||
/// Default OFF for the canary release, then default-on (matching `PUNKTFUNK_10BIT`'s
|
||||
/// explicit-off grammar). It gates the whole feature — spawn flags included — so an operator
|
||||
/// who hits a bad interaction can turn the gamescope backend back into exactly today's 8-bit
|
||||
/// path with one env var and no downgrade path to trip over.
|
||||
/// Default ON (explicit-off grammar, matching `PUNKTFUNK_10BIT`) since the post-0.22.3 flip:
|
||||
/// the capability chain behind it (the `+pfhdr` banner probe, managed spawn, the client's
|
||||
/// 10-bit cap, the per-source downgrade latch) keeps a stock-gamescope box on today's 8-bit
|
||||
/// path, so the knob's remaining job is the emergency escape hatch — an operator who hits a
|
||||
/// bad interaction sets `=0` and the gamescope backend is exactly the old SDR path again,
|
||||
/// spawn flags included.
|
||||
pub gamescope_hdr: bool,
|
||||
/// `PUNKTFUNK_GAMESCOPE_SDR_NITS` — the luminance SDR content is mapped to inside the PQ
|
||||
/// container of an HDR gamescope session (gamescope's `--hdr-sdr-content-nits`, default 400).
|
||||
@@ -270,7 +272,7 @@ impl HostConfig {
|
||||
// its first frames at all; `=0` is the A/B + escape hatch.
|
||||
gamescope_splash: env_on("PUNKTFUNK_GAMESCOPE_SPLASH").unwrap_or(true),
|
||||
// Default OFF for one canary release (design §4 rollout), then flip the `unwrap_or`.
|
||||
gamescope_hdr: env_on("PUNKTFUNK_GAMESCOPE_HDR").unwrap_or(false),
|
||||
gamescope_hdr: env_on("PUNKTFUNK_GAMESCOPE_HDR").unwrap_or(true),
|
||||
gamescope_sdr_nits: val("PUNKTFUNK_GAMESCOPE_SDR_NITS")
|
||||
.and_then(|s| s.trim().parse::<u32>().ok())
|
||||
.filter(|n| (1..=10_000).contains(n)),
|
||||
|
||||
@@ -49,6 +49,7 @@ printf '\n[punktfunk]\nServer = https://git.unom.io/api/packages/unom/arch/$repo
|
||||
```sh
|
||||
sudo pacman -Sy punktfunk-host # the streaming host
|
||||
sudo pacman -S punktfunk-web # optional: the browser management console (pairing + status)
|
||||
sudo pacman -S punktfunk-gamescope # optional: HDR (10-bit BT.2020 PQ) off gamescope sessions
|
||||
sudo usermod -aG input "$USER" # /dev/uinput access for virtual gamepads (re-login to apply)
|
||||
```
|
||||
|
||||
@@ -155,5 +156,7 @@ sudo pacman -U punktfunk-host-*.pkg.tar.zst
|
||||
|
||||
NVENC/EGL come from the NVIDIA driver (`nvidia-utils`); on a GPU-less builder, symlink the CUDA
|
||||
stub into the link path first (the `PKGBUILD` header documents this). Full details, the
|
||||
Fedora→Arch dependency map, and the SteamOS systemd-sysext path are in
|
||||
Fedora→Arch dependency map, and the systemd-sysext mechanism are in
|
||||
[`packaging/arch/README.md`](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/arch/README.md).
|
||||
(For a **SteamOS host**, use the [on-device installer](/docs/steamos-host) instead — it builds
|
||||
the host and the HDR gamescope against the running OS.)
|
||||
|
||||
@@ -152,9 +152,9 @@ These apply to the **Gaming Mode (gamescope)** path; the KDE Desktop path is una
|
||||
current gamescope is fine; this only bites if you've pinned an old one.
|
||||
- **The mouse cursor isn't included in the captured image** — a gamescope limitation for now. (The
|
||||
KDE Desktop path renders the cursor normally.)
|
||||
- **HDR needs the punktfunk gamescope build** (`punktfunk-gamescope`, shipped in the sysext) plus
|
||||
`PUNKTFUNK_GAMESCOPE_HDR=1`. Without it sessions stream SDR — correctly, including SDR versions
|
||||
of HDR games.
|
||||
- **HDR needs the punktfunk gamescope build** (`punktfunk-gamescope`, shipped in the sysext) and
|
||||
is attempted by default when it is present (`PUNKTFUNK_GAMESCOPE_HDR=0` forces SDR). Without
|
||||
the build sessions stream SDR — correctly, including SDR versions of HDR games.
|
||||
|
||||
Canonical list: [gamescope → Known limits](/docs/gamescope#known-limits).
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ the full picture (and [Bazzite](/docs/bazzite) for that distro's specifics).
|
||||
| `PUNKTFUNK_GAMESCOPE_SESSION` | `steam` | The host owns a `gamescope-session-plus` (Steam) session at the client's mode (headless appliance; no physical session running). |
|
||||
| `PUNKTFUNK_GAMESCOPE_NODE` | `auto` · node id | Discover + capture a **running** gamescope's PipeWire node at a fixed mode. Do **not** combine with `SESSION`. |
|
||||
| `PUNKTFUNK_GAMESCOPE_APP` | command | For an ad-hoc bare-gamescope session, the nested command to run (e.g. `vkcube`). |
|
||||
| `PUNKTFUNK_GAMESCOPE_HDR` | `1` · `0` *(default off)* | Allow HDR (10-bit BT.2020 PQ) sessions on the gamescope backend. Needs the `punktfunk-gamescope` build — see [HDR on gamescope](/docs/gamescope#hdr-on-gamescope). Without it, or without the build, sessions stream SDR. |
|
||||
| `PUNKTFUNK_GAMESCOPE_HDR` | `1` · `0` *(default on)* | Allow HDR (10-bit BT.2020 PQ) sessions on the gamescope backend. Needs the `punktfunk-gamescope` build — see [HDR on gamescope](/docs/gamescope#hdr-on-gamescope); without the build, sessions stream SDR. Set `0` to force SDR. |
|
||||
| `PUNKTFUNK_GAMESCOPE_SDR_NITS` | e.g. `400` | On an HDR gamescope session, the luminance SDR content (desktop, Steam overlay, SDR games) is mapped to inside the PQ container. Unset = gamescope's own default of 400. |
|
||||
| `PUNKTFUNK_GAMESCOPE_BIN` | path | Force a specific gamescope binary for the sessions the host spawns. Unset = prefer `punktfunk-gamescope` on `PATH`, then `gamescope`. |
|
||||
| `PUNKTFUNK_SESSION_WATCH` | `1` · `0` | Follow a Gaming ↔ Desktop switch **mid-stream** (rebuild the backend in place, no reconnect). **On by default** on Bazzite/SteamOS; set `0` to disable. |
|
||||
@@ -92,7 +92,7 @@ See your desktop page ([KDE](/docs/kde), [GNOME](/docs/gnome)) for when to set t
|
||||
| Setting | Values | Meaning |
|
||||
|---|---|---|
|
||||
| `PUNKTFUNK_FEC_PCT` | `N` (percent) | Forward-error-correction redundancy for lossy links (the default is sensible for a normal LAN). Higher = more loss-resilient, more bandwidth. |
|
||||
| `PUNKTFUNK_10BIT` | `1` · `0` *(default on)* | HEVC Main10 / HDR. **On by default** — the host permits 10-bit; a session goes 10-bit only when the client advertises it (behind the client's HDR setting). Set `0` to force 8-bit. Windows host, plus the Linux **GNOME 50+ GameStream desktop mirror** (`PUNKTFUNK_VIDEO_SOURCE=portal`, mirrored monitor in HDR mode — check with `punktfunk-host hdr-probe`). Also the Linux **gamescope** backend with the `punktfunk-gamescope` build + `PUNKTFUNK_GAMESCOPE_HDR=1`. The other Linux virtual displays (Mutter, KWin, wlroots) stay 8-bit: their virtual-monitor screencasts are SDR-only upstream. |
|
||||
| `PUNKTFUNK_10BIT` | `1` · `0` *(default on)* | HEVC Main10 / HDR. **On by default** — the host permits 10-bit; a session goes 10-bit only when the client advertises it (behind the client's HDR setting). Set `0` to force 8-bit. Windows host, plus the Linux **GNOME 50+ GameStream desktop mirror** (`PUNKTFUNK_VIDEO_SOURCE=portal`, mirrored monitor in HDR mode — check with `punktfunk-host hdr-probe`). Also the Linux **gamescope** backend with the `punktfunk-gamescope` build (on by default too). The other Linux virtual displays (Mutter, KWin, wlroots) stay 8-bit: their virtual-monitor screencasts are SDR-only upstream. |
|
||||
| `PUNKTFUNK_444` | `1` · `0` *(default on)* | Full-chroma HEVC 4:4:4 (Range Extensions) — sharper text/desktop, no chroma loss. **On by default** on the host; the client's own 4:4:4 setting (default off) is the real switch. Set `0` to force 4:2:0. **punktfunk/1 native only** (Moonlight stays 4:2:0), HEVC-only, honored only when the client advertises 4:4:4 **and** the GPU supports it (probed; NVENC is the validated path — VAAPI/AMF/QSV decline). Independent of 10-bit. |
|
||||
| `PUNKTFUNK_CHACHA20` | `1` · `0` *(default on)* | ChaCha20-Poly1305 session encryption for clients without hardware AES (old ARM TVs, e.g. webOS), lifting their ~100 Mbps software-AES decrypt ceiling. **On by default** on the host; a session uses it only when the client requests it — everyone else stays on AES-GCM. Purely a performance choice (both ciphers are full-strength); set `0` to force AES-GCM for all sessions. |
|
||||
| `PUNKTFUNK_PYROWAVE_MAX_MBPS` | `N` (Mbps) | Cap the [PyroWave](/docs/pyrowave) Automatic bitrate pin, for a host on a link that the open-loop pin can outrun (e.g. 4:4:4 + HDR at 5120×1440@240 pins ~5.3 Gbps, over a 5GbE link). Unset = no cap. Only affects Automatic (bitrate `0`) PyroWave sessions; an explicit client bitrate bypasses it. |
|
||||
|
||||
@@ -113,7 +113,7 @@ a model. See the full [Configuration reference](/docs/configuration) for every o
|
||||
| `PUNKTFUNK_GAMESCOPE_NODE` | `auto` · node id | Discover and capture a **running** gamescope's PipeWire node at a fixed mode. Do **not** combine with `SESSION`. |
|
||||
| `PUNKTFUNK_GAMESCOPE_APP` | command | For an ad-hoc bare-gamescope session, the nested command to run (e.g. `vkcube`). |
|
||||
| `PUNKTFUNK_SESSION_WATCH` | `1` · `0` | Follow a Gaming ↔ Desktop switch mid-stream (rebuild in place, no reconnect). On by default on Bazzite/SteamOS; set `0` to disable. |
|
||||
| `PUNKTFUNK_GAMESCOPE_HDR` | `1` · `0` *(default off)* | Allow HDR (10-bit BT.2020 PQ) sessions. Needs `punktfunk-gamescope` — see below. |
|
||||
| `PUNKTFUNK_GAMESCOPE_HDR` | `1` · `0` *(default on)* | Allow HDR (10-bit BT.2020 PQ) sessions. Needs `punktfunk-gamescope` (SDR otherwise) — see below. Set `0` to force SDR. |
|
||||
| `PUNKTFUNK_GAMESCOPE_SDR_NITS` | e.g. `400` | On an HDR session, how bright SDR content (the desktop, the Steam overlay, an SDR game) is inside the PQ container. gamescope's default is 400. |
|
||||
| `PUNKTFUNK_GAMESCOPE_BIN` | path | Force a specific gamescope binary. Otherwise the host prefers `punktfunk-gamescope` on `PATH`, then `gamescope`. |
|
||||
|
||||
@@ -130,17 +130,14 @@ To stream real HDR you need `punktfunk-gamescope`: gamescope plus a small patch
|
||||
own name and does **not** replace your system gamescope — your Gaming Mode keeps using that one.
|
||||
|
||||
- **Bazzite / Fedora Atomic** — included in the punktfunk sysext; `punktfunk-sysext update` gets it.
|
||||
- **Arch / SteamOS** — the `punktfunk-gamescope` package.
|
||||
- **NixOS** — `services.punktfunk.host.gamescopeHdr = true;` (it also sets the env var below).
|
||||
- **Arch** — the `punktfunk-gamescope` package.
|
||||
- **SteamOS (Steam Deck installer)** — built and wired automatically by
|
||||
`scripts/steamdeck/install.sh` / `update.sh`.
|
||||
- **NixOS** — `services.punktfunk.host.gamescopeHdr` (default `true`).
|
||||
- **Anything else** — `bash packaging/gamescope/build-punktfunk-gamescope.sh` from the source tree.
|
||||
|
||||
Then turn it on:
|
||||
|
||||
```sh
|
||||
PUNKTFUNK_GAMESCOPE_HDR=1
|
||||
```
|
||||
|
||||
and check what the host thinks it can do:
|
||||
HDR is attempted by default once the build is present (`PUNKTFUNK_GAMESCOPE_HDR=0` forces SDR).
|
||||
Check what the host thinks it can do:
|
||||
|
||||
```sh
|
||||
punktfunk-host hdr-probe
|
||||
@@ -186,8 +183,8 @@ These apply to the **Gaming Mode (gamescope)** path only; the desktop path is un
|
||||
- **HDR needs the punktfunk gamescope build.** A stock gamescope's capture output is 8-bit SDR, so
|
||||
sessions stream SDR — correctly, including SDR versions of HDR games. Install
|
||||
`punktfunk-gamescope` (gamescope plus a small patch that teaches its capture node the 10-bit
|
||||
BT.2020 PQ formats) and set `PUNKTFUNK_GAMESCOPE_HDR=1`, and a 10-bit-capable client streams
|
||||
true HDR10. See [HDR on gamescope](#hdr-on-gamescope) below.
|
||||
BT.2020 PQ formats), and a 10-bit-capable client streams true HDR10 — no knob needed.
|
||||
See [HDR on gamescope](#hdr-on-gamescope) below.
|
||||
|
||||
To stream the KDE Plasma desktop of a Steam box instead, see [KDE Plasma](/docs/kde). To bring up the
|
||||
web console and pair a client, see [The Web Console](/docs/web-console).
|
||||
|
||||
@@ -105,7 +105,7 @@ see [Status & Progress](/docs/status).
|
||||
(`PUNKTFUNK_VIDEO_SOURCE=portal`) negotiates the 10-bit PQ formats and encodes HEVC Main10
|
||||
BT.2020 PQ. The **gamescope** virtual output is no longer blocked either — the
|
||||
`punktfunk-gamescope` build carries the small patch its capture node was missing, so
|
||||
`PUNKTFUNK_GAMESCOPE_HDR=1` streams true HDR10 (on-glass validation pending; the patch is
|
||||
installing it streams true HDR10 by default (on-glass validation pending; the patch is
|
||||
offered upstream as
|
||||
[gamescope#2126](https://github.com/ValveSoftware/gamescope/issues/2126)). What stays blocked
|
||||
upstream is HDR on **Mutter's virtual monitors** — `RecordVirtual` streams are still SDR-only
|
||||
|
||||
@@ -40,7 +40,7 @@ host is newer than the Linux host.)
|
||||
mirror an HDR monitor over the GameStream desktop-capture source
|
||||
(`PUNKTFUNK_VIDEO_SOURCE=portal`): the portal negotiates the 10-bit PQ screencast formats GNOME
|
||||
50 added and encodes Main10 PQ. And a **gamescope** host can stream HDR off its virtual output
|
||||
with the `punktfunk-gamescope` build plus `PUNKTFUNK_GAMESCOPE_HDR=1` — games get real HDR
|
||||
with the `punktfunk-gamescope` build (on by default when installed) — games get real HDR
|
||||
surfaces and the composite is captured as 10-bit BT.2020 PQ. (Run `punktfunk-host hdr-probe` to
|
||||
check either; both are pending on-glass validation.) The **other** Linux virtual displays —
|
||||
Mutter, KWin, wlroots — still stream 8-bit: their virtual-monitor screencasts are SDR-only
|
||||
|
||||
@@ -126,6 +126,22 @@ streams it at your client's resolution; in Desktop Mode it streams the KDE deskt
|
||||
auto-detects which session is live per connection. See [Steam / gamescope](/docs/gamescope) for the
|
||||
attach-vs-managed detail and known limits.
|
||||
|
||||
## HDR (10-bit BT.2020 PQ)
|
||||
|
||||
The installer also builds `punktfunk-gamescope` — gamescope plus the small patch that adds the
|
||||
10-bit PQ formats to its capture node (see [HDR on gamescope](/docs/gamescope#hdr-on-gamescope)) —
|
||||
and points the host at it. Nothing to configure: with it in place, a 10-bit-capable client with
|
||||
HDR enabled streams true HDR10 from Game Mode; anything missing and the session streams 8-bit SDR
|
||||
instead (never a mislabelled picture). Check what the host resolved with:
|
||||
|
||||
```sh
|
||||
~/punktfunk/target-steamos/release/punktfunk-host hdr-probe
|
||||
```
|
||||
|
||||
The build is best-effort: if it fails, the installer says so loudly and everything else keeps
|
||||
working in SDR — re-run `update.sh` to retry. `PUNKTFUNK_GAMESCOPE_HDR=0` in
|
||||
`~/.config/punktfunk/host.env` forces SDR deliberately.
|
||||
|
||||
## Updating
|
||||
|
||||
After pulling new source, rebuild and restart in one step (config + pairings persist):
|
||||
|
||||
@@ -138,6 +138,7 @@ package_punktfunk-host() {
|
||||
optdepends=('pipewire-pulse: PulseAudio-API audio from games/apps (real `pulseaudio` also works)'
|
||||
'nvidia-utils: NVENC hardware encode + GPU EGL/CUDA zero-copy (REQUIRED to encode on NVIDIA)'
|
||||
'gamescope: per-session nested compositor backend (no desktop login needed) — needs >=3.16.22'
|
||||
'punktfunk-gamescope: HDR (10-bit BT.2020 PQ) streaming on the gamescope backend — attempted by default when installed'
|
||||
'kwin: stream a KDE Plasma desktop (kwin VirtualDisplay backend)'
|
||||
'mutter: stream a GNOME desktop (Mutter RecordVirtual backend)'
|
||||
'sway: stream a wlroots desktop (Sway VirtualDisplay backend)'
|
||||
|
||||
+21
-12
@@ -114,28 +114,37 @@ NVENC/EGL come from the NVIDIA driver: `sudo pacman -S --needed nvidia-utils`. A
|
||||
| NVIDIA driver (NVENC/EGL/CUDA) | `nvidia-utils` *(optdepend — never a hard dep)* |
|
||||
| Compositor backends | `gamescope` (≥3.16.22) / `kwin` / `mutter` / `sway` *(optdepends)* |
|
||||
|
||||
## SteamOS 3 (immutable) — use a systemd-sysext
|
||||
## Immutable Arch (SteamOS 3) — the systemd-sysext mechanism
|
||||
|
||||
SteamOS has a **read-only `/usr` on A/B partitions**, and every OS update reimages the rootfs —
|
||||
so `steamos-readonly disable` + `pacman` (and flatpak/distrobox) are fragile or unusable for a
|
||||
host that needs `/dev/uinput`, `/dev/uhid`, the host PipeWire socket, the GPU render node, and the
|
||||
right to spawn a compositor. The update-survivable, SteamOS-blessed mechanism is a
|
||||
**systemd-sysext**: an overlay image merged read-only over `/usr` at boot, living in the writable
|
||||
`/var/lib/extensions/` (so it persists across A/B updates, no readonly-disable).
|
||||
so `steamos-readonly disable` + `pacman` is fragile for anything that must survive updates. The
|
||||
SteamOS-blessed overlay mechanism is a **systemd-sysext**: an image merged read-only over `/usr`
|
||||
at boot, living in the writable `/var/lib/extensions/`.
|
||||
|
||||
> **For a SteamOS HOST this is NOT the supported path** — that is
|
||||
> [`scripts/steamdeck/install.sh`](../../scripts/steamdeck/) (the on-device distrobox build,
|
||||
> which also builds the HDR gamescope). A host sysext carries a prebuilt binary that breaks on
|
||||
> the next SteamOS soname bump, and `/var` — where sysexts live — is per-A/B-partition-set.
|
||||
> The mechanism below is what the Deck **client** image uses (next section), and an option for
|
||||
> operators on other immutable Arch derivatives who accept the prebuilt trade-off.
|
||||
|
||||
Build the package, then wrap its `/usr` payload into a sysext image:
|
||||
```sh
|
||||
# 1. build the pacman package (needs an Arch environment / container)
|
||||
# 1. build the pacman packages (needs an Arch environment / container)
|
||||
cd packaging/arch && PF_SRCDIR="$(git rev-parse --show-toplevel)" makepkg -f --holdver
|
||||
# 2. turn it into a sysext .raw (extracts the package's /usr into an image + extension-release)
|
||||
bash build-sysext.sh punktfunk-host-*.pkg.tar.zst
|
||||
# 3. on the SteamOS box:
|
||||
( cd ../gamescope && makepkg -f -d --holdver ) # optional: the HDR gamescope companion
|
||||
# 2. turn it into a sysext .raw (extracts the packages' /usr into an image + extension-release);
|
||||
# --gamescope folds the HDR build into a HOST image (verified by its +pfhdr banner)
|
||||
bash build-sysext.sh --gamescope ../gamescope/punktfunk-gamescope-*.pkg.tar.zst punktfunk-host-*.pkg.tar.zst
|
||||
# 3. on the box:
|
||||
sudo cp punktfunk-host.raw /var/lib/extensions/
|
||||
sudo systemctl enable --now systemd-sysext # merges it; survives OS updates
|
||||
sudo systemctl enable --now systemd-sysext # merges it
|
||||
systemctl --user enable --now punktfunk-host # the user unit is now under /usr/lib
|
||||
```
|
||||
The udev rule, sysctl, and systemd **user** unit all live under `/usr/lib`, so the merged sysext
|
||||
exposes them. `systemd-sysext refresh` re-merges after a reboot.
|
||||
exposes them. `systemd-sysext refresh` re-merges after a reboot. (One HDR nuance of the sysext
|
||||
path: file capabilities don't survive it, so gamescope runs without `CAP_SYS_NICE` — everything
|
||||
works, frame pacing is marginally worse than the pacman install, whose `.install` sets the cap.)
|
||||
|
||||
## Steam Deck — the client (what the Decky plugin launches)
|
||||
|
||||
|
||||
@@ -5,15 +5,34 @@
|
||||
# disable`. Works for either split package — on a Steam Deck you'd wrap the CLIENT. Needs
|
||||
# `bsdtar`/`tar`, `squashfs-tools` (mksquashfs).
|
||||
#
|
||||
# Usage: bash build-sysext.sh <punktfunk-{host,client}-*.pkg.tar.zst>
|
||||
# Usage: bash build-sysext.sh [--gamescope <punktfunk-gamescope-*.pkg.tar.zst>] \
|
||||
# <punktfunk-{host,client}-*.pkg.tar.zst>
|
||||
# Output: <pkgname>.raw (e.g. punktfunk-client.raw)
|
||||
#
|
||||
# --gamescope folds the HDR-capable gamescope companion package (packaging/gamescope) into a HOST
|
||||
# image as /usr/bin/punktfunk-gamescope — what lets the gamescope backend stream 10-bit BT.2020 PQ
|
||||
# instead of 8-bit SDR (the host prefers that name on PATH and attempts HDR by default). Mirrors
|
||||
# the Bazzite image's fold-in, including the honesty check: the binary is verified by executing
|
||||
# its `+pfhdr` banner, never trusted by filename. Omit it and the image is exactly what it was —
|
||||
# the host then stays SDR on that backend, by design. (No CAP_SYS_NICE inside the image: file
|
||||
# capabilities don't survive this squashfs path — gamescope runs without it, pacing slightly
|
||||
# worse, same as the Bazzite sysext.)
|
||||
set -euo pipefail
|
||||
|
||||
PKG="${1:?usage: build-sysext.sh <punktfunk-{host,client}-*.pkg.tar.zst>}"
|
||||
GAMESCOPE=""
|
||||
if [ "${1:-}" = "--gamescope" ]; then
|
||||
GAMESCOPE="${2:?--gamescope needs a punktfunk-gamescope package}"; shift 2
|
||||
fi
|
||||
# No braces in the message: a literal `}` inside ${1:?...} terminates the expansion early and
|
||||
# corrupts $PKG (the tail of the message gets appended to the value — a real field bug).
|
||||
PKG="${1:?usage: build-sysext.sh [--gamescope <pkg>] <punktfunk-host|client pkg.tar.zst>}"
|
||||
[ -f "$PKG" ] || { echo "no such package: $PKG" >&2; exit 1; }
|
||||
# Derive the package name from the file (pkgname is everything before the -<version>).
|
||||
NAME="$(basename "$PKG" | sed -E 's/-[0-9].*//')"
|
||||
[ -n "$NAME" ] || { echo "could not derive package name from $PKG" >&2; exit 1; }
|
||||
if [ -n "$GAMESCOPE" ] && [ "$NAME" != "punktfunk-host" ]; then
|
||||
echo "--gamescope only makes sense for a punktfunk-host image (got: $NAME)" >&2; exit 1
|
||||
fi
|
||||
|
||||
STAGE="$(mktemp -d)"
|
||||
trap 'rm -rf "$STAGE"' EXIT
|
||||
@@ -26,6 +45,25 @@ else
|
||||
tar -C "$STAGE" -xf "$PKG" usr
|
||||
fi
|
||||
|
||||
# The HDR gamescope companion (see --gamescope in the header). Verified by its banner marker
|
||||
# rather than trusted by filename: an unpatched gamescope shipped under this name would make the
|
||||
# host promise HDR it cannot deliver, and the punktfunk/1 Welcome cannot take that back
|
||||
# mid-session. Executing the staged binary needs a build box the binary runs on (the Arch CI
|
||||
# container qualifies; it built it).
|
||||
if [ -n "$GAMESCOPE" ]; then
|
||||
[ -f "$GAMESCOPE" ] || { echo "no such package: $GAMESCOPE" >&2; exit 1; }
|
||||
if command -v bsdtar >/dev/null 2>&1; then
|
||||
bsdtar -C "$STAGE" -xf "$GAMESCOPE" usr
|
||||
else
|
||||
tar -C "$STAGE" -xf "$GAMESCOPE" usr
|
||||
fi
|
||||
GS_BIN="$STAGE/usr/bin/punktfunk-gamescope"
|
||||
[ -x "$GS_BIN" ] || { echo "$GAMESCOPE did not provide usr/bin/punktfunk-gamescope" >&2; exit 1; }
|
||||
"$GS_BIN" --version 2>&1 | grep -q '+pfhdr' || {
|
||||
echo "$GAMESCOPE's binary has no +pfhdr marker — it is not a punktfunk HDR build" >&2; exit 1; }
|
||||
echo "folded in $("$GS_BIN" --version 2>&1 | head -1)"
|
||||
fi
|
||||
|
||||
# The marker systemd-sysext requires to merge the image. ID=_any merges onto ANY host os-release
|
||||
# (SteamOS, Arch, Bazzite); ARCHITECTURE pins it to x86-64 so it's never merged on the wrong arch.
|
||||
install -d "$STAGE/usr/lib/extension-release.d"
|
||||
|
||||
@@ -40,9 +40,10 @@ PUNKTFUNK_GAMESCOPE_ATTACH=1
|
||||
#
|
||||
# HDR (10-bit BT.2020 PQ) on the gamescope path. Needs `punktfunk-gamescope` — gamescope plus the
|
||||
# patch that teaches its capture node the 10-bit formats — which the sysext ships alongside the
|
||||
# host; it does NOT replace the system gamescope. Off by default while the feature soaks; a host
|
||||
# without the patched binary stays SDR either way. `punktfunk-host hdr-probe` says what it found.
|
||||
# PUNKTFUNK_GAMESCOPE_HDR=1
|
||||
# host; it does NOT replace the system gamescope. ON by default when that binary is present; a
|
||||
# host without it stays SDR either way. `punktfunk-host hdr-probe` says what it found. To force
|
||||
# SDR on the gamescope backend:
|
||||
# PUNKTFUNK_GAMESCOPE_HDR=0
|
||||
#
|
||||
# On an HDR session, how bright SDR content (desktop, Steam overlay, SDR games) is inside the PQ
|
||||
# container. gamescope's default is 400 nits; raise it if whites look dim on your TV.
|
||||
|
||||
@@ -166,19 +166,16 @@ in
|
||||
|
||||
gamescopeHdr = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
default = true;
|
||||
description = ''
|
||||
Put `punktfunk-gamescope` — gamescope carrying punktfunk's `pipewire-hdr` patches — on
|
||||
the host service's PATH and turn HDR on for the gamescope backend
|
||||
(`PUNKTFUNK_GAMESCOPE_HDR=1`), so a 10-bit-capable client can stream true HDR10
|
||||
(BT.2020 PQ) off a gamescope virtual output.
|
||||
the host service's PATH, so a 10-bit-capable client can stream true HDR10 (BT.2020 PQ)
|
||||
off a gamescope virtual output. HDR is attempted by default once the binary is present
|
||||
(`PUNKTFUNK_GAMESCOPE_HDR=0` in `settings`/`environmentFile` forces SDR).
|
||||
|
||||
It does NOT replace the system's `gamescope`: the binary has its own name and the host
|
||||
prefers it only for the sessions it spawns itself. Costs a gamescope build from source.
|
||||
|
||||
Off by default while the feature soaks (design §4 rollout); the host also stays SDR on
|
||||
its own if the patched binary is somehow absent, so this is a policy switch, not a
|
||||
promise.
|
||||
prefers it only for the sessions it spawns itself. Costs a gamescope build from source
|
||||
— set `false` to skip that build; the host then stays SDR on the gamescope backend.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -365,9 +362,9 @@ in
|
||||
(optional (cfg.host.settings != { }) "${hostSettingsFile}")
|
||||
++ (optional (cfg.host.environmentFile != null) "-${toString cfg.host.environmentFile}");
|
||||
};
|
||||
# Layered UNDER `settings`/`environmentFile` (systemd's Environment= loses to a later
|
||||
# EnvironmentFile), so an explicit `PUNKTFUNK_GAMESCOPE_HDR` in either still wins.
|
||||
environment = mkIf cfg.host.gamescopeHdr { PUNKTFUNK_GAMESCOPE_HDR = "1"; };
|
||||
# No PUNKTFUNK_GAMESCOPE_HDR here: the host defaults it on, and the capability probe on
|
||||
# the resolved binary keeps a build-less box SDR. `gamescopeHdr` only controls whether
|
||||
# the patched binary is on PATH; `settings`/`environmentFile` can still set =0 to force SDR.
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@ serving HTTPS (HTTP/1.1 over TLS) with the host's identity cert), so its service
|
||||
|
||||
| Script | What it does |
|
||||
|--------|--------------|
|
||||
| `install.sh` | Idempotent installer: ensure the `pf2` distrobox + toolchain → build host + web + **plugin runner** → write config → tune sysctl + udev + `vhci-hcd` + `input` group and **register it on SteamOS's atomic-update keep list** (sudo) → install + start `punktfunk-host` / `punktfunk-web` systemd **user** services with linger, plus the **rebuild check** below. |
|
||||
| `update.sh` | Rebuild everything from the current source and restart the services (config + pairings persist). `--pull` does `git pull` first. Also retrofits anything a newer install.sh writes (runner, keep-list registration, rebuild check) onto older installs. |
|
||||
| `rebuild-check.sh` | The post-OS-update self-heal (run by `punktfunk-rebuild-check.service` before the host at session start): `ldd`-probes the binary — milliseconds when healthy, a full `update.sh` rebuild only when a SteamOS update actually broke its library links. |
|
||||
| `install.sh` | Idempotent installer: ensure the `pf2` distrobox + toolchain → build host + web + **plugin runner** → write config → build the **HDR gamescope** below → tune sysctl + udev + `vhci-hcd` + `input` group and **register it on SteamOS's atomic-update keep list** (sudo) → install + start `punktfunk-host` / `punktfunk-web` systemd **user** services with linger, plus the **rebuild check** below. |
|
||||
| `update.sh` | Rebuild everything from the current source and restart the services (config + pairings persist). `--pull` does `git pull` first. Also retrofits anything a newer install.sh writes (runner, HDR gamescope, keep-list registration, rebuild check) onto older installs. |
|
||||
| `build-gamescope.sh` | Build gamescope + the `pipewire-hdr` patches (`packaging/gamescope`) in the same distrobox and install it as `~/.local/bin/punktfunk-gamescope`, wiring `PUNKTFUNK_GAMESCOPE_BIN` into `host.env` — what lets Game Mode stream **10-bit BT.2020 PQ (HDR)** instead of 8-bit SDR. Best-effort: a failure warns and the host streams SDR. Content-stamped — a no-op unless `packaging/gamescope/` changed or the binary broke. |
|
||||
| `rebuild-check.sh` | The post-OS-update self-heal (run by `punktfunk-rebuild-check.service` before the host at session start): `ldd`-probes the host binary **and the HDR gamescope** — milliseconds when healthy, a full `update.sh` rebuild only when a SteamOS update actually broke library links. |
|
||||
|
||||
```sh
|
||||
git clone https://git.unom.io/unom/punktfunk ~/punktfunk
|
||||
@@ -74,6 +75,13 @@ default `pf2`), `PUNKTFUNK_MGMT_PORT` (47990), `PUNKTFUNK_WEB_PORT` (47992).
|
||||
- **Plugin runner:** the deb's payload laid out user-scoped (read-only `/usr` can't take the
|
||||
package): wrapper `~/.local/bin/punktfunk-scripting`, pinned `bun` in
|
||||
`~/.local/lib/punktfunk-scripting/`, bundle in `~/.local/share/punktfunk-scripting/`.
|
||||
- **HDR gamescope:** `~/.local/bin/punktfunk-gamescope` (gamescope + the `pipewire-hdr` patches,
|
||||
built in `pf2`, run natively — it does **not** replace the system gamescope; only the sessions
|
||||
the host spawns use it). `host.env` gains `PUNKTFUNK_GAMESCOPE_BIN=` pointing at it — a line
|
||||
`build-gamescope.sh` maintains and removes again if the binary ever stops working, because a
|
||||
stale absolute override would break session spawning, not just HDR. HDR is attempted by
|
||||
default when present; `PUNKTFUNK_GAMESCOPE_HDR=0` in `host.env` forces SDR. Verify with
|
||||
`punktfunk-host hdr-probe`.
|
||||
- **System tuning (sudo):** `/etc/sysctl.d/99-punktfunk-net.conf` (32 MB UDP buffers — the #1
|
||||
high-bitrate lever), `/etc/udev/rules.d/60-punktfunk.rules` (`uinput`/`uhid` access),
|
||||
`/etc/modules-load.d/punktfunk.conf` (`vhci-hcd` for the native Deck pad), `$USER` in the `input`
|
||||
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bash
|
||||
# punktfunk — build the HDR-capable `punktfunk-gamescope` for a SteamOS host (called by
|
||||
# install.sh and update.sh; safe to run by hand).
|
||||
#
|
||||
# Stock gamescope offers no 10-bit PQ formats on its PipeWire capture node, so every session on
|
||||
# the gamescope backend stays 8-bit SDR. This builds gamescope + punktfunk's `pipewire-hdr`
|
||||
# patches (the ONE canonical recipe, packaging/gamescope/build-punktfunk-gamescope.sh) inside the
|
||||
# same Debian-trixie distrobox the host is built in, installs it as
|
||||
# ~/.local/bin/punktfunk-gamescope, and pins the host to it via PUNKTFUNK_GAMESCOPE_BIN in
|
||||
# host.env. HDR is on by default in the host; with this binary present a 10-bit-capable client
|
||||
# streams true HDR10 from Game Mode.
|
||||
#
|
||||
# BEST-EFFORT BY DESIGN, mirroring the CI packaging paths: streaming works without it (sessions
|
||||
# stay SDR), so a failure here warns loudly and exits 0 — it must never cost the host install or
|
||||
# update it runs inside. The one hard rule is honesty at the seams: host.env points at the binary
|
||||
# ONLY while `--version` proves it runs on SteamOS glass and carries the `+pfhdr` marker; on any
|
||||
# failure both the binary and the host.env line are removed (a stale absolute override would
|
||||
# otherwise break gamescope session spawning entirely, which is worse than SDR).
|
||||
#
|
||||
# The build clones gamescope fresh each run (submodules included). That costs bandwidth, but it
|
||||
# only runs when the packaging/gamescope tree changed (pin bump, patch change — tracked by a
|
||||
# content stamp) or the installed binary stopped working; a no-op re-run is milliseconds.
|
||||
set -euo pipefail
|
||||
|
||||
log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m ok\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m !!\033[0m %s\n' "$*" >&2; }
|
||||
|
||||
SRC="${PUNKTFUNK_SRC:-$HOME/punktfunk}"
|
||||
BOX="${PUNKTFUNK_BOX:-pf2}"
|
||||
GS_BIN="$HOME/.local/bin/punktfunk-gamescope"
|
||||
STAMP="$HOME/.local/share/punktfunk/gamescope.stamp"
|
||||
HOST_ENV="$HOME/.config/punktfunk/host.env"
|
||||
PKGDIR="$SRC/packaging/gamescope"
|
||||
|
||||
# host.env may only name the binary while it verifiably works (see header). sed -i is fine: the
|
||||
# file is ours (install.sh §3) and the line is one this script wrote.
|
||||
unwire() {
|
||||
[ -f "$HOST_ENV" ] || return 0
|
||||
if grep -q '^PUNKTFUNK_GAMESCOPE_BIN=' "$HOST_ENV"; then
|
||||
sed -i '/^# HDR gamescope built by scripts\/steamdeck/d;/^PUNKTFUNK_GAMESCOPE_BIN=/d' "$HOST_ENV"
|
||||
warn "host.env: removed PUNKTFUNK_GAMESCOPE_BIN (no working punktfunk-gamescope) — sessions stream SDR"
|
||||
fi
|
||||
}
|
||||
wire() {
|
||||
[ -f "$HOST_ENV" ] || return 0 # install.sh runs this after §3 wrote host.env; by-hand runs may predate it
|
||||
grep -q '^PUNKTFUNK_GAMESCOPE_BIN=' "$HOST_ENV" && return 0
|
||||
printf '\n# HDR gamescope built by scripts/steamdeck/build-gamescope.sh (10-bit BT.2020 PQ capture;\n# rebuilt by update.sh; PUNKTFUNK_GAMESCOPE_HDR=0 forces SDR).\nPUNKTFUNK_GAMESCOPE_BIN=%s\n' "$GS_BIN" >> "$HOST_ENV"
|
||||
ok "host.env: PUNKTFUNK_GAMESCOPE_BIN=$GS_BIN"
|
||||
}
|
||||
# The on-glass truth: the binary must RUN ON STEAMOS (not merely in the build container — this is
|
||||
# the ABI seam the whole distrobox approach exists for) and carry the +pfhdr banner marker.
|
||||
verifies() { [ -x "$GS_BIN" ] && "$GS_BIN" --version 2>&1 | head -1 | grep -q '+pfhdr'; }
|
||||
|
||||
[ -d "$PKGDIR/patches" ] || { warn "no $PKGDIR — skipping the HDR gamescope build"; exit 0; }
|
||||
|
||||
# Content stamp over the packaging tree: a pin bump or patch edit re-triggers the build; anything
|
||||
# else makes this a fast no-op.
|
||||
want_stamp="$(find "$PKGDIR" -type f | LC_ALL=C sort | xargs sha256sum | sha256sum | cut -d' ' -f1)"
|
||||
if [ -f "$STAMP" ] && [ "$(cat "$STAMP")" = "$want_stamp" ] && verifies; then
|
||||
ok "punktfunk-gamescope up to date ($("$GS_BIN" --version 2>&1 | head -1))"
|
||||
wire
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Building punktfunk-gamescope (HDR 10-bit capture; ~5-10 min, best-effort)"
|
||||
# gamescope's build deps in the box (trixie names, mirroring packaging/gamescope/PKGBUILD — keep
|
||||
# the two lists in step). Provisioned here, not in install.sh's main pass, so a dep problem can
|
||||
# only ever cost this feature. glm/stb come in as meson wraps; wlroots/libliftoff/vkroots/
|
||||
# libdisplay-info are vendored submodules — none of those need packages.
|
||||
if ! distrobox enter "$BOX" -- bash -lc '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq --no-install-recommends \
|
||||
meson ninja-build cmake glslang-tools \
|
||||
libwayland-dev wayland-protocols libxkbcommon-dev \
|
||||
libx11-dev libxcomposite-dev libxdamage-dev libxext-dev libxmu-dev \
|
||||
libxrender-dev libxres-dev libxtst-dev libxxf86vm-dev libxcursor-dev \
|
||||
libxcb-errors-dev libxcb-icccm4-dev libxcb-ewmh-dev \
|
||||
libxcb1-dev libxcb-composite0-dev libxcb-render0-dev libxcb-xfixes0-dev \
|
||||
libxcb-shm0-dev libxcb-res0-dev libxcb-present-dev libxcb-xinput-dev \
|
||||
libxcb-randr0-dev libxcb-dri3-dev libxcb-shape0-dev \
|
||||
libcap-dev libdrm-dev libinput-dev libudev-dev libseat-dev \
|
||||
libvulkan-dev libglm-dev libpixman-1-dev libeis-dev \
|
||||
libavif-dev libdecor-0-dev hwdata libluajit-5.1-dev \
|
||||
libpipewire-0.3-dev libspa-0.2-dev libsdl2-dev \
|
||||
xwayland liblcms2-dev >/dev/null
|
||||
' ; then
|
||||
warn "could not provision gamescope build deps in '$BOX' — sessions stay SDR (re-run update.sh to retry)"
|
||||
exit 0
|
||||
fi
|
||||
if ! distrobox enter "$BOX" -- bash -lc "
|
||||
set -e
|
||||
bash '$PKGDIR/build-punktfunk-gamescope.sh' --prefix \"\$HOME/.local\" --no-setcap
|
||||
"; then
|
||||
warn "punktfunk-gamescope failed to build — sessions stay SDR (re-run update.sh to retry)"
|
||||
unwire
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if verifies; then
|
||||
# CAP_SYS_NICE is gamescope's scheduling boost — worth it, never required. Filesystem caps
|
||||
# can't be set from the rootless box, so it happens here on the SteamOS side.
|
||||
if sudo -n true 2>/dev/null; then
|
||||
sudo setcap 'CAP_SYS_NICE=eip' "$GS_BIN" 2>/dev/null \
|
||||
&& ok "setcap CAP_SYS_NICE (frame-pacing boost)" \
|
||||
|| warn "could not setcap CAP_SYS_NICE (gamescope still works, pacing slightly worse)"
|
||||
fi
|
||||
mkdir -p "$(dirname "$STAMP")"
|
||||
printf '%s' "$want_stamp" > "$STAMP"
|
||||
wire
|
||||
ok "punktfunk-gamescope ready: $("$GS_BIN" --version 2>&1 | head -1)"
|
||||
else
|
||||
# Built in the box but does not run on SteamOS (an ABI/soname seam) or lacks the marker. A
|
||||
# broken binary must not linger where PATH or host.env could resolve it.
|
||||
warn "built binary failed its on-glass check on SteamOS — removing it; sessions stay SDR"
|
||||
"$GS_BIN" --version 2>&1 | head -3 >&2 || true
|
||||
rm -f "$GS_BIN" "$STAMP"
|
||||
unwire
|
||||
fi
|
||||
exit 0
|
||||
@@ -245,6 +245,14 @@ else
|
||||
[ "$WITH_WEB" = 1 ] && ok "web.env exists (login password unchanged)"
|
||||
fi
|
||||
|
||||
# --- 3b. HDR gamescope (punktfunk-gamescope, best-effort) ------------------
|
||||
# Stock gamescope offers only 8-bit capture, so Game Mode streams SDR. The punktfunk build adds
|
||||
# the 10-bit BT.2020 PQ formats, and the host attempts HDR by default the moment it is present
|
||||
# (PUNKTFUNK_GAMESCOPE_HDR=0 forces SDR). Best-effort by design: on any failure this warns and
|
||||
# the host streams SDR — see build-gamescope.sh, which also wires PUNKTFUNK_GAMESCOPE_BIN into
|
||||
# host.env only while the binary provably runs on SteamOS.
|
||||
PUNKTFUNK_SRC="$SRC" PUNKTFUNK_BOX="$BOX" bash "$SRC/scripts/steamdeck/build-gamescope.sh"
|
||||
|
||||
# --- 4. system tuning (needs sudo: UDP buffers + gamepad udev rule + vhci-hcd + input group) --------
|
||||
log "System tuning (UDP buffers + gamepad rules + vhci-hcd + input group)"
|
||||
# sudo was acquired up front in preflight (SUDO_OK) so this never stalls behind the long build; a
|
||||
|
||||
@@ -18,14 +18,29 @@ export PATH="$HOME/.local/bin:$PATH"
|
||||
SRC="${PUNKTFUNK_SRC:-$HOME/punktfunk}"
|
||||
BIN="$SRC/target-steamos/release/punktfunk-host"
|
||||
|
||||
NEED=0
|
||||
if [ ! -x "$BIN" ]; then
|
||||
echo "punktfunk-host binary missing at $BIN — running a full rebuild" >&2
|
||||
elif ! ldd "$BIN" 2>/dev/null | grep -q "not found"; then
|
||||
exit 0 # every library resolves — nothing to do
|
||||
else
|
||||
NEED=1
|
||||
elif ldd "$BIN" 2>/dev/null | grep -q "not found"; then
|
||||
echo "punktfunk-host no longer loads after a SteamOS update — its missing libraries:" >&2
|
||||
ldd "$BIN" 2>/dev/null | grep "not found" >&2 || true
|
||||
echo "rebuilding against the new OS tree (this takes a few minutes; streaming resumes after)" >&2
|
||||
NEED=1
|
||||
fi
|
||||
|
||||
# The HDR gamescope companion chases OS libraries the same way. Probe it only when host.env pins
|
||||
# it (build-gamescope.sh wires that line only while the binary works) — a break here would not
|
||||
# just lose HDR, it would break gamescope session SPAWNING via the stale absolute override, so it
|
||||
# rebuilds with the same urgency as the host binary.
|
||||
GS_BIN="$(sed -n 's/^PUNKTFUNK_GAMESCOPE_BIN=//p' "$HOME/.config/punktfunk/host.env" 2>/dev/null | head -1)"
|
||||
if [ -n "$GS_BIN" ]; then
|
||||
if [ ! -x "$GS_BIN" ] || ldd "$GS_BIN" 2>/dev/null | grep -q "not found"; then
|
||||
echo "punktfunk-gamescope no longer loads after a SteamOS update — rebuilding it" >&2
|
||||
NEED=1
|
||||
fi
|
||||
fi
|
||||
|
||||
[ "$NEED" = 0 ] && exit 0 # everything resolves — nothing to do (every normal boot)
|
||||
|
||||
exec bash "$SRC/scripts/steamdeck/update.sh"
|
||||
|
||||
@@ -52,6 +52,12 @@ sed 's|^ExecStart=.*|ExecStart=%h/.local/bin/punktfunk-scripting|' \
|
||||
systemctl --user daemon-reload
|
||||
ok "plugin runner rebuilt (opt-in service: systemctl --user enable --now punktfunk-scripting)"
|
||||
|
||||
# HDR gamescope (punktfunk-gamescope): rebuild when the packaging tree changed or the installed
|
||||
# binary stopped working — also RETROFITS it onto older installs that predate it (fast no-op
|
||||
# otherwise). Best-effort; on failure the host streams SDR (see build-gamescope.sh).
|
||||
log "HDR gamescope (punktfunk-gamescope)"
|
||||
PUNKTFUNK_SRC="$SRC" PUNKTFUNK_BOX="$BOX" bash "$SRC/scripts/steamdeck/build-gamescope.sh"
|
||||
|
||||
# Retrofit the post-OS-update rebuild check (install.sh §5) onto older installs: probes the host
|
||||
# binary with ldd at session start and re-runs this script when a SteamOS update broke its links.
|
||||
if [ ! -f "$HOME/.config/systemd/user/punktfunk-rebuild-check.service" ]; then
|
||||
|
||||
Reference in New Issue
Block a user