Skip to content

The DPU vsync counter is phoc's output rate, not the app's -- a browser scrolling at 30 fps and presenting video at 15 fps both read "60 fps, 0 jank

scope: generic · severity: trap · confidence: proven · subsystem: graphics

tools/ph-fps.py and tools/ph-gesture-bench.py read the DPU’s frame counter. That is the number of frames phoc sent to the panel. phoc repaints every vsync while any client is animating (and the video subsurface keeps it animating), so the counter sits at 60 whatever the client does. A client that updates its window every fourth vsync shows the same 60 as one that updates every vsync – the panel is simply shown the same client buffer four times, which is exactly the “frames repainting” the user reported.

Three different frame rates exist in a browser, and only one is on the panel:

stage how to read it YouTube on 2026-09-02
media pipeline -> WebKit compositor ph-webvq.py (getVideoPlaybackQuality via the inspector) 60/s, ~0 dropped
WebKit compositor -> its window (the app’s real frame rate) WAYLAND_DEBUG=1 commit intervals, or wp_presentation_feedback.presented sequence deltas 12-15 fps idle video, ~30 fps drag
phoc -> panel ph-fps.py / tk-gesture-bench 60

So: the DPU number is the control, never the verdict. For an app, count its own commits. WAYLAND_DEBUG=1 app 2>log, then intervals between -> wl_surface#N.commit() on the busiest surface; presented(...) args carry the vsync sequence, whose deltas are exact (4 = every fourth frame). youtube-judder-is-2160p60-plus-a-lockstep-decoder-not-venus-throughput was written against the DPU column and its “panel 60 vsync/s during every stutter” line is true and irrelevant; the earlier handoffs’ “0 jank” browser scroll and “60 vsync/s fullscreen VP9 in Epiphany” figures were phoc’s. porthole-dev/porthole#43 asks the bench to grow a client-side column.