Merge branch 'worktree-wave2-pw3-dmabuf-latch' into worktree-wave2-pyrowave
# Conflicts: # packaging/arch/punktfunk-host.install # scripts/steamdeck/install.sh
This commit is contained in:
@@ -12,9 +12,33 @@ _ensure_punktfunk_group() {
|
||||
getent group punktfunk >/dev/null 2>&1 || groupadd --system punktfunk 2>/dev/null || true
|
||||
}
|
||||
|
||||
# CAP_SYS_NICE on the host binary — the GPU-scheduling grant.
|
||||
#
|
||||
# WHY: PyroWave encodes on the GPU's shader cores, so a GPU-bound game starves it (measured: the
|
||||
# encode dispatch goes from ~2 ms to 15-18 ms at 95 % game load). The fix is an elevated
|
||||
# global-priority Vulkan queue, which the driver gates on CAP_SYS_NICE — measured 2026-08-08 on an
|
||||
# RTX 5070 Ti: WITHOUT the capability every priority class is refused, WITH it the encoder is
|
||||
# granted REALTIME on the first attempt. RADV is the same. Without this line the knob exists and
|
||||
# does nothing. Same capability, same mechanism, as our gamescope package sets on its own binary.
|
||||
#
|
||||
# NARROW: CAP_SYS_NICE only permits raising scheduling priority (nice/ioprio/affinity/RT class). It
|
||||
# grants no filesystem, network or user-switching privilege, and it is NOT setuid.
|
||||
#
|
||||
# TWO CONSEQUENCES worth knowing before you debug something odd on this host:
|
||||
# * a file capability makes the process AT_SECURE, so the dynamic loader IGNORES LD_LIBRARY_PATH
|
||||
# and LD_PRELOAD for it. A library-path shim that used to work will silently stop.
|
||||
# * core dumps are suppressed for capability-carrying binaries by default (fs.suid_dumpable).
|
||||
#
|
||||
# Never fails the install: a box without libcap, or a filesystem that cannot store capabilities
|
||||
# (some overlay/NFS setups), just runs at default priority exactly as before.
|
||||
_grant_sched_capability() {
|
||||
setcap 'cap_sys_nice=ep' usr/bin/punktfunk-host 2>/dev/null || true
|
||||
}
|
||||
|
||||
post_install() {
|
||||
_ensure_update_group
|
||||
_ensure_punktfunk_group
|
||||
_grant_sched_capability
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
udevadm trigger --subsystem-match=misc 2>/dev/null || true
|
||||
# Apply the UDP socket-buffer tuning now (also auto-applied at boot by systemd-sysctl).
|
||||
@@ -73,6 +97,8 @@ post_upgrade() {
|
||||
# root-only, and the virtual Steam Deck pad silently unable to attach. groupadd is idempotent, so
|
||||
# this is a no-op on boxes that installed fresh.
|
||||
_ensure_punktfunk_group
|
||||
# A replaced binary is a NEW inode — file capabilities do not survive the upgrade, so re-grant.
|
||||
_grant_sched_capability
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
sysctl -p /usr/lib/sysctl.d/99-punktfunk-net.conf >/dev/null 2>&1 || true
|
||||
_warn_stale_firewall_ports
|
||||
|
||||
@@ -130,6 +130,31 @@ SYSEXT_VERSION_ID=$PF_VR
|
||||
EXTENSION_RELOAD_MANAGER=1
|
||||
EOF
|
||||
|
||||
# CAP_SYS_NICE on the host binary — the GPU-scheduling grant. PyroWave encodes on the GPU shader
|
||||
# cores a game saturates, and the driver gates the elevated global-priority Vulkan queue that fixes
|
||||
# it on this capability (measured 2026-08-08 on an RTX 5070 Ti: refused without it, granted REALTIME
|
||||
# with it; RADV the same). Narrow — scheduling priority only, no filesystem/network privilege, not
|
||||
# setuid.
|
||||
#
|
||||
# It has to be applied HERE, not in the merge hook: a merged sysext's /usr is a read-only squashfs,
|
||||
# so nothing can setcap it afterwards. And it cannot ride in from the RPM either — the spec declares
|
||||
# it with %caps, but rpm stores capabilities in its own header and `rpm2cpio | cpio` carries only
|
||||
# the payload, so the staged file arrives with no capability at all. mksquashfs DOES record
|
||||
# security.capability (only security.selinux is excluded below), so a setcap on the staging tree is
|
||||
# what ends up in the image.
|
||||
#
|
||||
# Needs CAP_SETFCAP, i.e. root (or fakeroot) — a plain-user CI build cannot do it. That is not fatal:
|
||||
# the image just ships as it does today and the encode runs at default GPU priority, so warn and
|
||||
# carry on rather than fail a release build over a performance lever.
|
||||
if [ -f "$STAGE/usr/bin/punktfunk-host" ]; then
|
||||
if setcap 'cap_sys_nice=ep' "$STAGE/usr/bin/punktfunk-host" 2>/dev/null; then
|
||||
echo "granted CAP_SYS_NICE to usr/bin/punktfunk-host (GPU-priority lever active)"
|
||||
else
|
||||
echo "WARNING: could not setcap CAP_SYS_NICE (need root/CAP_SETFCAP) — the image will ship" >&2
|
||||
echo " without it and PyroWave will encode at default GPU priority." >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# SELinux labels as pseudo-xattrs (see header). matchpathcon resolves each target path against
|
||||
# the targeted policy's file_contexts; <<none>> means "no specific entry" — skip those (the
|
||||
# handful of matches all resolve to real contexts for our payload).
|
||||
|
||||
@@ -294,6 +294,16 @@ if [ "$1" = "configure" ]; then
|
||||
# primitive that must not ride on the group users are told to join for gamepads
|
||||
# (security-review 2026-08-05 M-4).
|
||||
getent group punktfunk >/dev/null 2>&1 || addgroup --system punktfunk 2>/dev/null || true
|
||||
# CAP_SYS_NICE — the GPU-scheduling grant. PyroWave encodes on the shader cores a game
|
||||
# saturates, and the driver gates the elevated global-priority Vulkan queue that fixes it on
|
||||
# this capability: measured 2026-08-08 on an RTX 5070 Ti, WITHOUT it every priority class is
|
||||
# refused and WITH it the encoder is granted REALTIME first try (RADV behaves the same).
|
||||
# Without this line the knob exists and does nothing. Narrow: it permits raising scheduling
|
||||
# priority only — no filesystem, network or user-switching privilege, and no setuid. Note a
|
||||
# capability-carrying binary is AT_SECURE, so the loader ignores LD_LIBRARY_PATH/LD_PRELOAD for
|
||||
# it and core dumps are suppressed by default. Best-effort: a box without libcap, or a
|
||||
# filesystem that cannot store capabilities, just runs at default priority as before.
|
||||
setcap 'cap_sys_nice=ep' /usr/bin/punktfunk-host 2>/dev/null || true
|
||||
# Pick up the /dev/uinput rule without a reboot (best-effort, no-op in containers).
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
udevadm trigger --subsystem-match=misc 2>/dev/null || true
|
||||
|
||||
@@ -356,6 +356,26 @@ in
|
||||
allowedUDPPorts = nativeUDP ++ optionals cfg.host.gamestream gamestreamUDP;
|
||||
};
|
||||
|
||||
# CAP_SYS_NICE — the GPU-scheduling grant. PyroWave encodes on the GPU shader cores a game
|
||||
# saturates; the elevated global-priority Vulkan queue that fixes it is gated on this
|
||||
# capability (measured 2026-08-08, RTX 5070 Ti: without it EVERY priority class is refused,
|
||||
# with it the encoder gets REALTIME on the first attempt; RADV behaves the same).
|
||||
#
|
||||
# NixOS cannot `setcap` a store path — it is read-only and shared — so this goes through
|
||||
# `security.wrappers`, which builds a small setcap'd wrapper in /run/wrappers/bin. The unit's
|
||||
# ExecStart points at the wrapper below; everything else about the host is unchanged.
|
||||
#
|
||||
# Narrow: CAP_SYS_NICE permits raising scheduling priority only — no filesystem, network or
|
||||
# user-switching privilege, and the wrapper is capability-based, NOT setuid. Two side effects
|
||||
# to know: the wrapped binary is AT_SECURE (the loader ignores LD_LIBRARY_PATH/LD_PRELOAD for
|
||||
# it) and core dumps are suppressed by default.
|
||||
security.wrappers.punktfunk-host = {
|
||||
source = "${cfg.host.package}/bin/punktfunk-host";
|
||||
capabilities = "cap_sys_nice=ep";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
systemd.user.services.punktfunk-host = {
|
||||
description = "punktfunk GameStream + punktfunk/1 streaming host";
|
||||
documentation = [ "https://git.unom.io/unom/punktfunk" ];
|
||||
@@ -374,8 +394,12 @@ in
|
||||
# PUNKTFUNK_GAMESCOPE_BIN so an operator's own override of that env still wins.
|
||||
++ optional cfg.host.gamescopeHdr cfg.host.gamescopePackage;
|
||||
serviceConfig = {
|
||||
# Through the wrapper (see `security.wrappers.punktfunk-host` above), NOT the store path
|
||||
# directly — the store path carries no capability and the GPU-priority lever would be
|
||||
# inert. `config.security.wrapperDir` rather than a hard-coded /run/wrappers/bin so an
|
||||
# operator who has moved it is still correct.
|
||||
ExecStart =
|
||||
"${cfg.host.package}/bin/punktfunk-host serve" + optionalString cfg.host.gamestream " --gamestream";
|
||||
"${config.security.wrapperDir}/punktfunk-host serve" + optionalString cfg.host.gamestream " --gamestream";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 2;
|
||||
EnvironmentFile =
|
||||
|
||||
@@ -477,7 +477,15 @@ install -Dm0644 scripts/punktfunk-scripting.service %{buildroot}%{_userunitdir}/
|
||||
%files
|
||||
%license LICENSE-MIT LICENSE-APACHE THIRD-PARTY-NOTICES.txt
|
||||
%doc README.md packaging/README.md
|
||||
%{_bindir}/punktfunk-host
|
||||
# CAP_SYS_NICE — the GPU-scheduling grant, declared the RPM-native way so rpm applies it at
|
||||
# install, restores it on upgrade, and VERIFIES it (a plain %post setcap does none of those).
|
||||
# PyroWave encodes on the shader cores a game saturates; the elevated global-priority Vulkan queue
|
||||
# that fixes it is gated on this capability. Measured 2026-08-08 on an RTX 5070 Ti: without it
|
||||
# every priority class is refused, with it the encoder gets REALTIME first try (RADV the same).
|
||||
# Narrow — scheduling priority only, no filesystem/network/user-switching privilege, not setuid.
|
||||
# Consequences: the binary becomes AT_SECURE, so the loader ignores LD_LIBRARY_PATH/LD_PRELOAD for
|
||||
# it, and core dumps are suppressed by default.
|
||||
%caps(cap_sys_nice=ep) %{_bindir}/punktfunk-host
|
||||
%{_bindir}/punktfunk-tray
|
||||
%{_udevrulesdir}/60-punktfunk.rules
|
||||
%dir %{_libexecdir}/punktfunk
|
||||
|
||||
Reference in New Issue
Block a user