Repository navigation
Why FPS drops: P-frame reference collapse #287
mauricio-gg
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary. FPS drops on the Vita are caused by the network, not by the Vita: a lost frame that FEC cannot repair breaks the H.264 reference chain, and every later P-frame fails until a new keyframe (IDR) arrives. The Vita decode path is not the bottleneck (decode averaged 1.7 ms against a 33 ms frame budget). The February 2026 fixes (faster IDR requests, cascade skip) are in
main; the proactive soft restart ("cascade alarm") from the same investigation was disabled and has since been removed. The IDR round trip turned out to be far slower than this investigation assumed; see the #251 IDR-wait freeze thread.Root cause: network-driven reference chain collapse
FPS drops are not caused by Vita-side bottlenecks. The decode design has no queue pressure:
overwrites=0in healthy sessions confirmed decode and render stay in sync.The chain of events:
target_bitratesteps down and never recovers mid-session (sessions 11782861312 and 18107437792; PR fix(congestion): report post-FEC effective loss to stop PS5 bitrate ratchet (GH #206) #213 / GH Wi-Fi burst jitter + receive-queue overflow drive PS5 bitrate floor-throttling (post-GH #188 track) #206 fixed loss being reported before FEC could recover it, which had been driving the ratchet down needlessly).Evidence from two February 2026 sessions
Only the measurements that do not depend on the later-discredited metrics are kept. The original table also had RTT and "measured bitrate" rows. The RTT row came from the fabricated readout (handshake RTT plus control-channel EWMA, see the #251 IDR-wait freeze thread), and the measured-bitrate row used a frame-count-divided figure that PR #193 found to seesaw between 0 and ~2 Mbps even on a healthy stream. Both rows are dropped as invalid. The session IDs for these two sessions were not recorded.
Why session 3 was smooth: a 5 second cooldown between sessions let Wi-Fi settle, the stream context was fresh with no accumulated corruption, and the first I-frame and following P-frames arrived intact, so no cascade started.
Constants: what the document said, and what is true on
main(0e9dd13)The old document quoted its constants at
lib/src/videoreceiver.c:18-19(it listed 200 ms / 2000 ms in one table and 100 ms / 1000 ms in its status table). Neither location is right any more.mainIDR_REQUEST_COOLDOWN_MSlib/src/videoreceiver.c:49IDR_REQUEST_TIMEOUT_MSlib/src/videoreceiver.c:50CASCADE_SKIP_THRESHOLDlib/src/videoreceiver.c:51(used at:658)VIDEO_GAP_REPORT_HOLD_MSvideoreceiver.c:15VIDEO_GAP_REPORT_FORCE_SPANvideoreceiver.c:17UNIT_SLOTS_MAXlib/src/frameprocessor.c:39LOSS_RECOVERY_ACTION_COOLDOWN_USvita/src/host_recovery.c:9RECONNECT_RECOVER_LOW_FPS_TRIGGER_WINDOWShost_recovery.c:13RECONNECT_RECOVER_TARGET_KBPShost_recovery.c:17FAST_RESTART_BITRATE_CAP_KBPShost_recovery.c:19LOSS_RETRY_BITRATE_KBPSvita/include/host_constants.h:3STUCK_BITRATE_STREAK_THRESHOLDhandle_stuck_bitrateorSTUCK_BITRATE_*anywhere invita/orlib/Also stale in the old text: the reference store is 8 slots, not 16 (
lib/include/chiaki/videoreceiver.h:22, PR #186; see the motion macroblocking thread), and the video jitter ceiling on the Vita is now 40 ms (lib/src/takion.c:85, PR #195), not 100 ms.Improvement opportunities and what became of each
videoreceiver.c:826). It trims the client-side delay but cannot shorten the console's own ~1 s answer time.videoreceiver.c:658-669). Shipped. The old text said the saved ~55 ms per frame blocked the Takion thread; since PR feat(video): decouple sceAvcdecDecode from Takion recv thread (GH #188) #199 decode runs on its own thread (VitaDecode), so that blocking argument no longer applies.handle_cascade_alarmno longer exists. Only leftover state fields and a log line remain (vita/include/stream_state.h:249-251,vita/src/host_metrics.c:211-214, 773). The library's own soft-restart ladder was removed by PR fix(session): hands-off recovery after transport death (#272) #274, and recovery now reconnects from the UI thread after a transport death.lib/src/congestioncontrol.cstill reports every 200 ms (:5) with the loss clamp at 10% (:11). Note the clamp does not prevent the ratchet: any non-zero reported loss steps the bitrate down.rssi=in the PIPE/FPS line (vita/src/host_metrics.c:528-530,:759), with no trend tracking or action.The cascade flow, in short
Wi-Fi instability -> packet loss -> FEC cannot recover a frame -> frame dropped, IDR requested -> P-frames arrive during the wait and fail on the missing reference (each is reported to diagnostics, and each re-requests IDR if the cooldown allows) -> IDR arrives and the chain is restored -> if Wi-Fi is still unstable, a new cascade starts.
One correction to the original flow chart: it said failing frames were "forwarded to decoder (decode-anyway)". They were not. With
succ = falsethe frame never reached the decoder, which is exactly why the picture froze. Forwarding them is what PR #257 does behind its toggle (lib/src/videoreceiver.c:821-846).Original hardware results (February 2026)
P0 and P1a worked as designed, pending full validation at the time. P1b (cascade alarm) was disabled because of the Takion v12 handshake failures described above. The original verification plan (move twice as far from the router and compare cascade recovery time and frames lost per cascade) has no recorded results in the repo.
Source: docs/ai/FPS_HEALTH_INVESTIGATION.md (deleted from the repo in #281; recoverable from git history at commit 0e9dd13)
All reactions