Skip to content

fix(present): no-vsync fullscreen present flood + fullscreen direct scanout (Phase A + Phase B) - #124

Open
ariel3259 wants to merge 13 commits into
joske:masterfrom
ariel3259:fix/fullscreen-novsync-stutter
Open

fix(present): no-vsync fullscreen present flood + fullscreen direct scanout (Phase A + Phase B)#124
ariel3259 wants to merge 13 commits into
joske:masterfrom
ariel3259:fix/fullscreen-novsync-stutter

Conversation

@ariel3259

Copy link
Copy Markdown
Contributor

Summary

A no-vsync fullscreen game (CS2) made the server stutter: page_flip/s collapsed from refresh (~60) to 27–47 Hz because every PresentOptionAsync present re-composed the full 1920×1080 scene. This PR fixes the present flood at the core and enables fullscreen direct scanout (Phase A + Phase B).

What changed

Phase A — async present defer + supersession (core)

  • Park async presents while a flip is in flight (22674c7e): a PresentOptionAsync arriving mid-flip no longer re-composes; it parks.
  • Async successors supersede parked async predecessors (ca88a14b): a newer async present scraps the parked one (Xorg scrap semantics), so the flood coalesces to roughly one present per flip.
  • Superseded async victims get their Skip with eff=0 (225551f4): immediate gate, outside the synced hold-back.
  • Synced-present behavior is bit-for-bit unchanged.

Phase B — fullscreen direct scanout (KMS)

  • Unredirected fullscreen windows are the authoritative root (6182aa52): their presents become direct-scanout eligible.
  • Fullscreen explicit-sync presents accepted on the direct path (37bd6c0c).
  • Fullscreen sources are pre-probed before admission (2d7ab515), with the atomic TEST_ONLY m1 probe.
  • Degrade failed composed unflip instead of exiting the server (4c98c3fd): if the synchronized atomic unflip fails, fall back to per-output composed flips without releasing the still-scanned dma-buf or killing the session.
  • Late-materialization store ref (e10f4cbd): a deferred store ref is recorded for Pictures whose backing materializes late, fixing the game-start transparency bug where free_pixmap destroyed a drawable under a live Picture.
  • cargo +nightly fmt across the Phase A/B changes (3fa1ec7c).

Key design decisions

  1. options=0x8 is NOT async. The original finding assumed PresentOptionAsync; 0x8 is PresentOptionSuboptimal (synced). The observable fix on the nvidia box comes from the pre-existing synced supersession + the merged DRI3 syncobj fixes (PR feat(dri3): serve DRI3 1.4 syncobjs through DRM #122); Phase A addresses the spec's genuinely-async flood case, which a conforming client can still hit.
  2. Direct scanout requires the HW cursor (m1 guard cursor_hw). On nvidia-drm the HW cursor strategy is off by default, so Phase B does not engage on the nvidia box unless overridden (YSERVER_HW_CURSOR_NVIDIA=1, follow-up PR). This is the plan's known software-cursor blocker, recorded as a blocker rather than a regression.
  3. Spec compliance goal with Xorg as ground truth — the async scrap mirrors present_vblank_scrap in Xorg's present.c.

Hardware validation (2026-08-12, nvidia box, CS2 no-vsync, Cinnamon)

  • page_flip/s holds 59.8–61.0 through the flood (was 27–47).
  • present_skips/s coalesces at a 266/s median.
  • The stutter is gone; no visual or interaction regressions observed.
  • m1_probe_pass=0 with no rejects/errors (HW cursor precondition unmet on this box).

Files

  • crates/yserver-core/src/core_loop/process_request.rs — async defer/supersession + Skip eff=0.
  • crates/yserver-core/src/present_scheduler.rs — successor/scrap scheduling.
  • crates/yserver/src/kms/render/backend.rs — authoritative root, explicit-sync direct path, m1 pre-probe, composed-unflip degradation, late store ref.
  • Docs: finding (2026-08-11-cs2-fullscreen-novsync-pageflip-collapse.md), transparency-bug finding, spec (2026-08-11-async-present-defer-supersession.md), plan (2026-08-11-fullscreen-direct-scanout.md), status.md.

Testing

  • cargo test -p yserver --lib — 798 passed.
  • cargo test -p yserver-core --lib — 1154 passed.
  • cargo clippy --all-targets -- -D warnings — clean.

Dependency for reviewers

This branch is the base for the follow-up direct-scanout latest-wins supersession PR (feat/direct-scanout-latest-wins), which should be reviewed only after this one lands.

…ializes late

A Picture created over a host xid whose backing is not yet in the store
took no incref (render_create_picture); a later free_pixmap then reached
refcount 0 and destroyed the drawable under the live Picture - the
game-start transparency bug. Record a deferred ref and apply it when the
backing materializes (store_alloc), so the store refcount always pins a
picture's drawable regardless of materialization timing.
…een stutter

- findings: CS2 fullscreen no-vsync page-flip collapse (root cause + two
  adversarial review rounds)
- spec: async present defer + supersession (the primary flood fix)
- plan: 9-task TDD implementation plan (Phase A async defer, Phase B
  direct scanout efficiency)
- findings: transparency bug mechanism confirmed and fixed
- handoff doc for the transparency test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant