hosts/linux - Issues keeping up at high refresh rates #9
Open
opened 2026-07-28 14:32:55 +00:00 by enricobuehler
·
1 comment
No Branch/Tag Specified
main
worktree-flatpak-skia-099-pin
worktree-debian-ubuntu-support
worktree-wowlan-support
worktree-decky-shortcut-dup
worktree-vk-level-gate-clamp
worktree-edition-2024
worktree-win-sleep-blockers
worktree-rt-gpu-priority-defaults
worktree-black-stream-fixes
worktree-edid-lock-toggle
worktree-gate-double-arm-fix
chore/rust-safety-programme
worktree-console-pinned-profile-library
worktree-blackscreen-fixes
build/web-silence-rollup-directive-warnings
worktree-android-console-visual-refresh
worktree-nixos-capped-compositor-exe-denied
worktree-release-0270
worktree-dm-helper-diagnosis
worktree-gamescope-pin-bump-nobara
worktree-notes-capsysnice-correction
worktree-bazzite-docs-warning
worktree-kwin-capability-identification
worktree-gamescope-rpm-deb-builddeps
worktree-pyrowave-wire-dead-code
worktree-release-0260
worktree-cursor-composite-hardening
worktree-library-settings-origin-split
worktree-native-decode-m0
worktree-july-rpm-and-cursor
worktree-presenter-cadence-wp1
worktree-decky-brand-name
worktree-win-amd-decoder-order
worktree-stall-ride-through
fix/pad-audio-wasapi-module-path
feat/android-pad-audio
worktree-adl-emul-probe
worktree-haptics-m12-dry
worktree-haptics-m9-richfb
worktree-haptics-m11-settings
worktree-apple-store-screenshots
worktree-decky-slim-rework
worktree-appstore-copy
worktree-haptics-m10-wire
worktree-haptics-m8-proto
worktree-haptics-m7-windows
worktree-haptics-m6-presenter
worktree-wire-mtu-resilience
worktree-haptics-m5-android
worktree-haptics-m4-apple
worktree-haptics-m3-rumble-engine
worktree-android-presenter-023-triage
worktree-vdisplay-resume-recovery
worktree-kwin-vout-demirror
fix/web-console-sweep
fix/windows-web-console-lifecycle
chore/windows-rerender-semantics
fix/pf-encode-phase8
fix/pf-encode-phase7
feat/cursor-channel
feat/desktop-mouse-mode
feat/plugin-kit
fix/network-split-standing-latency
fix/windows-msix-arm64-and-manifest
fix/encode-medium-tier
fix/encode-rfi-taint-and-oob
fix/encode-init-leak-and-twin-drift
fix/encode-teardown-uaf
feat/pyrowave-windows
fix/ubuntu-2404-host-deb
fix/ios-archive-provisioning
merge/first-frame-latency
feat/shared-clipboard-v2
feat/apple-live-activities-widgets
debug/touch-finger-logging
feat/shared-clipboard
midstream-resize
plugin-kit-v0.4.1
v0.27.0
v0.26.0
plugin-kit-v0.4.0
sdk-v0.1.4
plugin-kit-v0.3.3
sdk-v0.1.3
plugin-kit-v0.3.2
v0.25.0
plugin-kit-v0.3.1
plugin-kit-v0.3.0
v0.24.0
v0.23.0
v0.22.3
v0.22.2
v0.22.1
v0.22.0
v0.21.0
v0.20.1
v0.20.0
plugin-kit-v0.2.0
v0.19.2
v0.19.1
v0.19.0
v0.18.0
v0.17.2
v0.17.1
v0.17.0
v0.16.0
v0.15.0
v0.14.0
v0.13.0
v0.12.0
v0.11.0
v0.10.1
v0.10.0
v0.9.2
v0.9.1
v0.9.0
v0.8.4
v0.8.3
v0.8.2
v0.8.1
v0.8.0
v0.7.4
v0.7.3
v0.7.2
v0.7.1
v0.7.0
v0.6.0
v0.5.1
v0.5.0
v0.4.2
v0.4.1
v0.4.0
v0.3.1
v0.3.0
v0.2.1
v0.2.0
v0.1.1
v0.1.0
Labels
No items
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: unom/punktfunk#9
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Multiple users have reported their stream not keeping up the full 120fps - needs further investigation
Triage notes, so the next report can be resolved in one round-trip instead of three.
Read the ratio first
The client HUD's
fpscounts received access units, not presented frames — so it is the host encode loop's iteration rate, and the client is exonerated by construction for this symptom. The host loop always encodes and sends a repeat when capture has no new frame (there is no skip-if-unchanged path), so received-AU rate == loop iteration rate.Under frame-driven pacing (default on) the loop sleeps to
t_cap + 0.9×interval, then waits for an arrival with a deadline ofnext + 0.5×interval. With no fresh arrival that returns at ≈t_cap + 1.5×interval→ rate = fps ÷ 1.5.So 0.667 × session fps is a signature, not a coincidence: 120 → exactly 80, 60 → 40. That keepalive is by design for a static desktop; seeing it while a game renders is the bug.
Discriminating the causes — they all land on the same HUD number
repeat_fpshigh, newfpslowfps≈ 80,repeat_fps≈ 0,submitp50 dominating the loop periodfpsat target but the client still feels shortEasiest ask for a reporter: the web-console stats capture, which already exposes both
fps("genuine NEW frames/s from the source") andrepeat_fps("re-encoded holds/s"). No env var, no log hunting.For more detail:
PUNKTFUNK_PERF=1givescapture diag: NEW frames from the source vs REPEATSplus thequeue/cap/submit/waitstage split.A/B lever:
PUNKTFUNK_FRAME_DRIVEN=0drops to the legacy fixed-grid tick, which paces at the full interval regardless of arrivals. If fps jumps toward target with it set, the arrival-wait keepalive is confirmed as the limiter.Two confounds worth knowing before blaming the host
FPS 80.00 / 12.50 ms) is Apple's Metal performance HUD measuring the app's Metal present rate, not stream arrivals.Already root-caused and fixed — check the reporter's version first
dff63b2a, in main). The stream-ordered gate forcedordered=falsefor any cursor-bearing frame, and gamescope re-attaches the live pointer to every frame → every frame paid a blocking copy plus a fence-waited Vulkan blend, ~10 ms CPU-blocked under the game's GPU load. This is the one that produced a measured 79 fps on a 120 fps session withrepeat_fps0.0 in all 73 samples.78fe77b0, in main) — presented as "random lag", not as a steady shortfall.Gap closed
The stats capture's
metarecorded id/started/duration/kind/w/h/fps/codec/client/sample_count — but not the encode backend or the GPU. A p50submitof 10 ms means "GPU CSC+encode throughput is the ceiling" on one backend and something else entirely on another, so every report so far cost a round-trip asking which one it was.encoder_backendandgpuare now recorded, taken from the record the encoder open itself writes (so it names the branch that really opened, rather than a re-derived guess).What is still needed to close this
Per-reporter, with versions: a stats capture (now self-describing), the compositor and its version, and whether frame generation is on. The remaining open question is whether the reports left over after
dff63b2aare a distinct cause or the same one on unpatched builds.