feat(scanout): direct-level latest-wins supersession — kill the direct/composed thrash - #125
Open
ariel3259 wants to merge 32 commits into
Open
feat(scanout): direct-level latest-wins supersession — kill the direct/composed thrash#125ariel3259 wants to merge 32 commits into
ariel3259 wants to merge 32 commits into
Conversation
…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
…-latest-wins # Conflicts: # docs/status.md
…nable The probe panicked on CI because the runner exposes /dev/dri entries it cannot open (Permission denied). Mirror the imported_syncobj render_node pattern: skip instead of fail when no card node can be opened.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Kills the direct/composed thrash of the Phase B direct-scanout path under a no-vsync fullscreen synced-present flood (CS2): after Phase B, the direct path flipped, unflipped, re-composed, and re-flipped —
page_flip/sfell to 54–56 and composed unflips hit ~553/session. With this PR the direct path holds steady at refresh and composed unflips drop to ~0.What changed
Two pieces, both scoped to the direct-scanout path (synced-present behavior on the composed path is bit-for-bit unchanged):
Piece 1 — the core sees the in-flight direct frame
present_flip_in_flight()andpresent_completion_is_idle()now countscanout_m2.pendingas a flip in flight (326299a9), so the core's existing parking + synced same-target supersession coalesce the flood to ~1 present/flip before the direct path.Piece 2 — direct-level latest-wins supersession (the queued slot)
DirectPresentFrameretains its probe framebuffer byArc(e6907993): the m1 cache owns anArc<DirectScanoutProbeFramebuffer>, so a queued frame survives an m1 cache clear (topology change) without a dangling handle or double-free.try_present_direct(1da50aa1): a present arriving while the direct flip is in flight goes into a singlescanout_m2.queuedslot (latest-wins) instead of tearing the direct frame down. A newer eligible present replaces the queued one (completed as Skip, per-window present_id ordering preserved).c16f7bae):retire_direct_outputpromotesqueued → pending;maybe_compositesubmits the promoted frame on the next tick. Includes the phantom-retire guard (a promoted-unsubmitted frame is NOT on the KMS pipe and must not consume scene retires).pending_is_submittedflag separates "in flight" from "promoted but unsubmitted" in themaybe_compositegate.Supporting changes
153a5a45): a queued victim's Skip (synced,effective_target_msc = 0) must not overtake a same-window smaller-present_identry still in the store.DRM_IOCTL_CRTC_QUEUE_SEQUENCEprobe without taking master (f948352b): live-session probe for the pacing fallback.7c207956):tools/yserver-cinnamon-hw-cs2.sh+ queued-slot Skip path logging.Arc, phantom-retire guard ordering,pending_is_submittedreset on teardown, chain-submit failure contract (release pins, complete as Skip/Copy, reentry-blocked), wake-pin single registration point.Key design decisions
queuedslot supersedes; a deeper (N>1) queue adds latency for no observable benefit (spec §Out of scope).present_id(synced only).YSERVER_HW_CURSOR_NVIDIA=1override (6dd4384f) is the A/B lever to engage Phase B on nvidia-drm (HW cursor disabled by default there); it is an opt-in, unchanged by this PR.Hardware validation (2026-08-13, nvidia box, CS2 no-vsync, Cinnamon,
YSERVER_HW_CURSOR_NVIDIA=1)page_flip/ssustained 60.0 during gameplay (was 54–56 pre-fix); the only sub-40 samples are session-exit teardown.composed unflip retired= 0 (was 553/session). Direct scanout stays engaged through the flood.m1_probe_pass=11,m1_probe_reject=0,m1_probe_error=0— Phase B engaged on the nvidia box this time (the earlier session sawm1_probe_pass=0becausecursor_hwwas false).chain direct submit failed= 0;chain-flip promoted+chain direct submitlines present.request_exit= none;missed_pageflips/s= 0;present_skips/smean 106 — the synced supersession keeps coalescing the flood.DRM_IOCTL_CRTC_QUEUE_SEQUENCEEOPNOTSUPPappears once at startup (NVIDIA absolute-vblank arm unsupported) → falls back to flip-driven MSC. Benign and pre-existing.Files
crates/yserver/src/kms/render/backend.rs— the whole direct-scanout state machine:ScanoutM2State.queued/pending_is_submitted,prepare_direct_frame,complete_queued_as_skip,submit_chain_direct_frame,retire_direct_output,maybe_composite,scanout_m1Arc cache.crates/yserver-core/src/core_loop/process_request.rs— Skip-ordering regression pin.crates/yserver/src/drm/page_flip.rs— CRTC queue-sequence probe.tools/yserver-cinnamon-hw-cs2.sh— hardware-validation harness.2026-08-12-direct-scanout-latest-wins-supersession-design.md), plan (3 adversarial rounds), findings update, handoff.Testing
cargo test -p yserver --lib— 807 passed.cargo test -p yserver-core --lib— 1155 passed.cargo clippy --all-targets -- -D warnings— clean.