The client now advertises VIDEO_CAP_10BIT|HDR and carries the result all the way to glass: - csc_rows is bit-depth exact (10-bit limited code points differ from 8-bit by ~half a code) and folds in the P010/X6 MSB-packing factor; new 10-bit white/black tests. - The CSC shader grows a params block: mode 0 passes the transfer through (SDR as-is, or PQ onto an HDR10 swapchain); mode 1 tonemaps PQ→SDR in-shader (ST.2084 EOTF, 203-nit reference white exposure, BT.2020→709, soft maxRGB rolloff, sRGB encode) for desktops without an HDR surface. PUNKTFUNK_TONEMAP_PEAK tunes the rolloff. - The presenter probes VK_EXT_swapchain_colorspace + an HDR10/ST.2084 10-bit surface format and flips modes in-band with the stream's PQ signaling: fence-quiesce, then CSC pass + video image (10-bit A2B10G10R10 intermediate — PQ in 8 bits bands) + overlay pipe + swapchain rebuild through the deferred-destroy rules. - P010 decodes through all three paths: Vulkan Video (X6 multiplanar pool, R10X6 plane views), VAAPI dmabuf (R16/RG1616 plane imports), software (swscale as before). - session pump advertises the caps; the host still gates Main10 behind its PUNKTFUNK_10BIT policy. Probed on glass hardware: the KDE/NVIDIA surface exposes A2B10G10R10+HDR10_ST2084, so true PQ passthrough is available there. Known v1 gaps: software-decode PQ shows untonemapped (8-bit RGBA carries the transfer baked); the SDR overlay composites unscaled onto an HDR10 surface (dim OSD); no vkSetHdrMetadataEXT yet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.1 KiB
title, description
| title | description |
|---|---|
| Hyprland | Configure a punktfunk host on a Hyprland session — headless output via hyprctl, capture via xdg-desktop-portal-hyprland. |
Hyprland is a first-class backend. The host adds a per-client headless output at the client's
exact mode with hyprctl, captures it through the xdg-desktop-portal-hyprland (xdph) ScreenCast
portal (zero-copy dmabuf), and injects input via the wlroots virtual pointer/keyboard protocols —
which Hyprland still implements even after dropping wlroots in v0.42.
This is a distinct backend from Sway / wlroots: Hyprland has its own IPC (hyprctl)
and its own portal (xdph), so it is auto-detected and driven separately.
This page assumes the package is already installed — see Arch, Ubuntu, or Fedora.
New here? Read Security & Safe Use first — a streaming host is remote control of the machine, so keep it on a trusted LAN or VPN and require pairing.
host.env
The host auto-detects a Hyprland session, so you usually need nothing here. To force the backend, set
these in ~/.config/punktfunk/host.env:
PUNKTFUNK_COMPOSITOR=hyprland
PUNKTFUNK_INPUT_BACKEND=wlr
PUNKTFUNK_VIDEO_SOURCE=virtual
# GPU zero-copy capture→encode is ON by default; auto-falls back to CPU. Set PUNKTFUNK_ZEROCOPY=0 to force CPU.
See Configuration for the full reference.
How it works
- Video — the host runs
hyprctl output create headless PF-1and applies a monitor rule for the client's exact mode. Outputs are named, so there's no before/after diffing. The rule useshyprctl keyword monitor …(the hyprlang config manager — the default on every release, 0.55 included) and falls back to the Luahyprctl eval 'hl.monitor{…}'only if you've opted into the Lua config manager. The host confirms the output actually adopted the mode before streaming. - Capture — it captures that output through the xdg-desktop-portal-hyprland (xdph) ScreenCast
portal. To pick the output without a GUI on a headless host, the host writes a managed
~/.config/hypr/xdph.confpointing xdph'scustom_picker_binaryat a small shim that selects the new output automatically — no interactive picker dialog to answer. - Input — mouse and keyboard are injected via the wlroots virtual pointer and virtual keyboard protocols (Hyprland kept them). Gamepads and audio are compositor-independent.
For how long the virtual output lives, and extend-vs-exclusive topology, see Virtual displays.
Requirements
- A running Hyprland session (any recent release; validate on both a ≤ 0.54 and a ≥ 0.55 install).
- xdg-desktop-portal-hyprland (xdph) installed and running — the host captures through its ScreenCast portal, and steers its custom picker. Without it there is no video.
- The ScreenCast interface routed to xdph — see
scripts/headless/portals.conf(a[Hyprland]section pinsorg.freedesktop.impl.portal.ScreenCast=hyprland).
Permission system
Hyprland's permission system (ecosystem.enforce_permissions, 0.49+, off by default) can deny
direct screencopy and virtual-input clients — and denial is silent: capture goes to black
frames and input is dropped, with no error. If you've enabled it, grant the host explicitly in
your Hyprland config:
ecosystem {
enforce_permissions = true
}
permission = /usr/bin/punktfunk-host, screencopy, allow
permission = /usr/bin/punktfunk-host, virtual-pointer, allow
permission = /usr/bin/punktfunk-host, virtual-keyboard, allow
The host logs a warning at startup when it detects enforcement is on. (Adjust the binary path to
where your package installed punktfunk-host.)
Start the host
With the backend selected, start the host from inside your Hyprland session:
systemctl --user enable --now punktfunk-host
journalctl --user -u punktfunk-host -f
Bring up the console and pair
Enable the web console, read its login password, and arm PIN pairing — see The Web Console. Then connect a client.