• v0.17.1
    audit / cargo-audit (push) Successful in 3m22s
    audit / bun-audit (push) Failing after 13s
    apple / swift (push) Successful in 1m23s
    ci / web (push) Successful in 55s
    ci / docs-site (push) Successful in 1m11s
    ci / bench (push) Successful in 5m12s
    apple / screenshots (push) Successful in 6m55s
    windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m55s
    windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m39s
    ci / rust (push) Successful in 24m5s
    decky / build-publish (push) Successful in 30s
    docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 19s
    docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 17s
    docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 40s
    docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 13s
    docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
    docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 10s
    android-screenshots / screenshots (push) Successful in 3m34s
    linux-client-screenshots / screenshots (push) Successful in 8m32s
    release / apple (push) Successful in 11m16s
    deb / build-publish-host (push) Successful in 12m51s
    deb / build-publish (push) Successful in 12m57s
    docker / deploy-docs (push) Successful in 27s
    web-screenshots / screenshots (push) Successful in 3m13s
    windows-host / package (push) Successful in 14m6s
    android / android (push) Successful in 15m33s
    arch / build-publish (push) Successful in 16m3s
    windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 2m43s
    windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m40s
    rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 17m10s
    rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 23m16s
    flatpak / build-publish (push) Successful in 7m9s
    Stable

    enricobuehler released this 2026-07-21 15:14:04 +00:00 | 2 commits to main since this release

    Wire-compatible with 0.17.x — existing pairings and clients keep working. WIRE_VERSION 2, driver protocol 4, and the embeddable C ABI 10 are all unchanged from 0.17.0, so hosts and clients negotiate exactly as before and no re-pairing is required.

    A fast-follow to 0.17.0, mostly on the Linux host: AMD Vulkan-Video encode is now zero-copy by default at every resolution, the Steam Deck host finally builds with the encoder it was always meant to use, HDR behaves on the new desktop-compositor HDR10 surfaces, and Intel-host streams get their colours back. On the macOS client, the long-standing windowed high-refresh kernel panic is fixed — with real HDR intact — and windowed present latency is roughly halved.

    AMD Linux encode is zero-copy by default

    The two zero-copy levers on the RADV Vulkan-Video encode path flip from opt-in to default, so an AMD Linux host encodes straight out of the capture buffer with no intermediate copy — at every mode, including unaligned ones like 1080p.

    • gamescope producer-native NV12, contributed by neoney. Capture now prefers gamescope's producer-side NV12 buffer and lets its RGB→YUV pass replace the host CSC entirely: the encoder imports the two-plane buffer directly as a video-encode source and the VCN encodes it in place. Contributed measurements on Van Gogh: encode p99 2.9 ms (down from ~4–4.5 ms on the previous RGB-direct path), 60 fps capture, zero send drops. PUNKTFUNK_PIPEWIRE_NV12=0 restores the packed-RGB negotiation.
    • True-size headers make it safe at 1080p. Native sessions now author the H.265 SPS / AV1 sequence header at the render size and pass the matching coded extent on every picture, so RADV programs the VCN with the true extent and edge-extends the alignment rows in hardware — the same mechanism VAAPI has always used — instead of staging through a padded copy. The wire bitstream is unchanged. RGB-direct's unaligned modes likewise default to the true-extent direct import; PUNKTFUNK_VULKAN_RGB_TRUE_EXTENT=0 restores the padded-copy staging. At 1080p the RGB true-extent path measured 5.38 ms p50, the fastest 1080p encode seen on that hardware.
    • Codec-aware gating protects everything else. The NV12 path only engages for H.265/AV1 sessions whose backend can open the raw Vulkan-Video encoder. H.264 / Moonlight (libav VAAPI), GameStream resolve, portal-mirror capture, PyroWave, and NVENC all keep their prior negotiation untouched.

    The Steam Deck host actually uses Vulkan encode now

    The SteamOS install/update scripts had been building the host featureless, so PlatformAuto could never select the Vulkan-Video backend and every Deck session silently fell back to libav VAAPI — unlike the deb/arch/rpm/sysext packages, which always shipped the feature.

    • install.sh / update.sh now build with --features punktfunk-host/vulkan-encode (pure-Rust ash, no new system dependency).
    • host.env sets RADV_PERFTEST=video_encode — Van Gogh's RADV still gates VK_KHR_video_encode_* behind it, so without it the backend can't even open.
    • The io.unom.Punktfunk.Host.desktop Exec is rewritten to the install's binary — KWin only grants screencast / fake-input to a .desktop-authorized executable, without which Desktop-Mode capture fails outright.

    update.sh retrofits the env and desktop changes idempotently, so existing installs pick them up without a reinstall. Validated on a SteamOS 3.8.14 Deck (Van Gogh): Vulkan HEVC now opens.

    Game Mode & session robustness on the Deck

    Three fixes for session transitions found live on a Deck host, where they could strand or kill a stream — or stop Game Mode from starting at all.

    • Stale WAYLAND_DISPLAY no longer breaks Game Mode. A dead desktop's socket was persisting in the systemd --user manager environment, so gamescope-session.target inherited it, ran nested, and aborted — autologin crash-looped until the variable was unset by hand. The manager env is now scrubbed when a desktop compositor goes away, with an UnsetEnvironment= belt on the takeover drop-in.
    • Capture-loss probes stop stealing the box session. A Game Mode → Desktop switch could land inside the 0.8 s gap before KDE came up; the capture-loss rebuild still read "Gaming" and restarted gamescope-session.target, yanking the user out of the KDE session they'd just chosen and killing the stream at the 40 s budget. A new counted rebuild_probe_scope makes probes attach-only for the first 4 s after a loss — no session takeover, no relaunch — while a genuine switch into Game Mode still gets its headless takeover.
    • Retries no longer burn the budget on a compositor that's gone. The pipeline retry loop couldn't tell a wait-it-out failure from a reconnect-now-and-it-works one: every gamescope bring-up ate the full 10 s first-frame budget, and a Desktop→Gaming switch spent 13 of its 27 s retrying against gone-KWin. The first attempt now reconnects at ~3 s to catch the gamescope first-frame race, and the capture-loss path retries in ~1 s detect-and-follow cycles.

    HDR & colour on Linux desktops

    GNOME 48 / Plasma 6 with Mesa ≥ 25.1 now expose HDR10 (ST2084) surfaces even on SDR desktops — a lane that was previously unreachable and never validated there.

    • Software-decoded frames stop going psychedelic. Fedora clients decode HEVC in software (stock Mesa strips hardware HEVC), and that sRGB content was being composed as PQ on the new HDR10 surfaces — the field-reported neon-soup picture. The CPU decode lane now keeps the SDR swapchain. Reproduced and fixed live on GNOME Wayland.
    • PUNKTFUNK_HDR10=0 pins the SDR shader tonemap, refusing the HDR10 swapchain outright — a diagnosis switch and field escape for the new desktop HDR10 path.
    • The session window gets its icon. Setting the Wayland app_id to io.unom.Punktfunk lets KWin / mutter match the shipped .desktop instead of showing the generic Wayland icon.

    Intel QSV colour (Windows)

    • SDR Intel-host streams carry a colour description again. The native QSV encoder only attached the colour signal info on HDR sessions, so SDR streams shipped with none — the field-reported blue/magenta Intel-host picture. It now writes BT.709 limited-range unconditionally, mirroring NVENC. Ships alongside new Intel-lane colour diagnostics (a vendor-selectable P010 self-test and unaligned-height colour-bar dumps) for chasing any remaining seams.

    macOS client: windowed HDR without the panic

    • The windowed high-refresh "mismatched swapID's" kernel panic is fixed. On a composited high-refresh session the CAMetalLayer async present queue (mandatory with displaySyncEnabled=false) could diverge from WindowServer's compositor and take down the box — it survived glass pacing and hit windowed HEVC on a 240 Hz Mac Studio, so it was the async queue itself, at any codec. Every windowed session now presents through a Core Animation transaction (presentsWithTransaction): commit, wait-until-scheduled, then present inside a CATransaction, so the swap lands in lockstep with the compositor instead of racing it. Fullscreen keeps the async path (direct scanout, lowest latency, no panic there).
    • Windowed HDR is real HDR again. The earlier stopgap routed windowed sessions through a BGRA8 IOSurface pool that couldn't carry HDR; extending it to HEVC would have tone-mapped windowed HDR down to SDR. That path is gone — the full rgba16Float / PQ / EDR render path is untouched (net −150 lines).
    • Windowed present latency roughly halved. The transactional present now commits from the render thread inside an explicit CATransaction + flush() instead of hopping to main (where a busy main thread batched presents at runloop rate). On a 240 Hz Studio, full-size window: display p50 18.6 ms → ~10.8 ms, presents 55/s → a clean 240 at a 4.17 ms cadence. A new windowedSafePresent setting (default ON = the safe transactional path) exposes the trade-off in the Settings (Presentation) pane; PUNKTFUNK_WINDOWED_PRESENT=async|transaction|surface overrides it for dev A/B.
    • The on-screen stats line is back on macOS 26. Its format string used %d for 64-bit Swift Int fields (fps / presents / lost); macOS 26's stricter String(format:) validator rejected the mismatch and dropped the whole line. Fixed to %lld.

    Compatibility: WIRE_VERSION 2, driver PROTOCOL_VERSION 4, C ABI 10 — all unchanged from 0.17.0. No API surface changed (api/openapi.json is bump-only). This is a patch release: existing hosts, clients, and embedders keep working after a straight recompile.

    Downloads