Skip to content

feat(scanout): promote eligible windows to KMS overlay planes#106

Open
nongio wants to merge 6 commits into
mainfrom
feat/window-scanout-new
Open

feat(scanout): promote eligible windows to KMS overlay planes#106
nongio wants to merge 6 commits into
mainfrom
feat/window-scanout-new

Conversation

@nongio

@nongio nongio commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Promotes eligible regular windows to KMS overlay planes: hides content_layer in the lay-rs scene (keeping the shadow) and appends the client surface as a ScanoutCandidate — no GPU compositing while the buffer updates
  • Top-to-bottom overlap selection: topmost window always promotes; a lower window promotes only when disjoint from everything above it (mutually disjoint, independent planes)
  • Stable gate disables promotion during: expose, app switcher, OSD, layer-shell overlay, tiling drop-zone, screencopy/screenshare capture, dock menu/hover/animation, windows overlapping the dock
  • Explicit-sync fix: adds DrmSyncPointBlocker from the surface acquire point so the KMS commit waits for the client GPU before the plane flips
  • Forces tiled windows to the Focused throttle state so the non-active half keeps full frame-rate
  • GPU sync after EGLImage→2D blit so composited buffers aren't sampled mid-upload
  • Demotion flicker fix: flushes re-imported buffer before unhiding content_layer

Test plan

  • Single window on screen — should scanout directly (verify with RUST_LOG=otto::scanout=debug)
  • Two non-overlapping windows — both promote to separate planes
  • Overlapping windows — only topmost promotes
  • Window overlapping dock — does not promote
  • Open expose / app switcher — scanout gates off
  • Screenshare active — scanout gates off
  • No tearing with explicit-sync enabled
  • Tiled window pair — both run at full frame-rate

@nongio nongio force-pushed the feat/window-placement branch from 6c88fc4 to b551af4 Compare June 24, 2026 07:59
nongio added 5 commits June 24, 2026 10:03
Promote eligible regular windows to KMS overlay planes: hide the
content_layer in the lay-rs scene (keeping the shadow) and append the
client surface above the scene as a ScanoutCandidate so the compositor
does no GPU compositing while the window's buffer updates.

- Top-to-bottom overlap selection: the topmost window plus any window
  disjoint from everything above it, so promoted windows are mutually
  disjoint on independent planes.
- Stable gate disables scanout during expose/window+workspace selection,
  app switcher, OSD, layer-shell overlay, the tiling drop-zone overlay,
  capture (screencopy/screenshare), dock menu/hover/animation, and for
  windows overlapping the dock.
- Fix explicit-sync (wp_linux_drm_syncobj) scanout tearing: add a
  DrmSyncPointBlocker from the surface acquire point in the pre-commit
  hook so the commit waits for the client GPU before the plane flips.
- Force tiled windows to the Focused throttle state so the non-active
  tiled half keeps full frame-rate.
- Add a GPU sync after the EGLImage->2D blit so composited client
  buffers aren't sampled mid-upload.
- Add org.otto.Compositor D-Bus TileLeft/TileRight/Maximize and an
  OTTO_NO_EXPLICIT_SYNC debug toggle for testing.

Builds on the in-tree window-tiling work (shared files).

Claude-Session: https://claude.ai/code/session_01MDkExLiMbHegicEBYigXcu
Remove the per-frame "scanout gate states" and "candidate eval" debug
traces added while diagnosing the dock-overlap and flapping issues.

Claude-Session: https://claude.ai/code/session_01MDkExLiMbHegicEBYigXcu
A scanned-out window rides a plane above the scene, so a Top/Overlay
layer-shell surface (notification daemon, panel) that overlaps it would
be hidden behind its plane. Reject promotion per-window when a visible
Top/Overlay layer surface overlaps the window, via layer_map_for_output
geometry. Overlap-aware so the always-present top bar only blocks the
windows it actually covers.

Replaces the previous blanket "any overlay surface visible disables all
scanout" gate, which both missed Top-layer notifications and over-fired.

Claude-Session: https://claude.ai/code/session_01MDkExLiMbHegicEBYigXcu
…icker

A window leaving the scanout set has its buffer re-imported into the scene,
but that happens in the draw phase, after the Phase-1 scene-damage prefetch
already ran. The consume site then reused the cached damage and skipped the
engine update, so the re-imported content was not flushed before compositing
and the first frame after demotion showed only the shadow. Re-run the engine
update (and force a draw) on frames where a window demoted; steady-state
frames are unaffected.

Claude-Session: https://claude.ai/code/session_01MDkExLiMbHegicEBYigXcu
@nongio nongio force-pushed the feat/window-scanout-new branch from 73d87b7 to 827e40b Compare June 24, 2026 08:04
@nongio nongio changed the base branch from feat/window-placement to main June 24, 2026 08:04
Closing expose snaps show_all_gesture to 0 the instant the spring is scheduled, so is_expose_transitioning() saw a settled state and let scanout promote mid-animation. Track the release animation with a dedicated expose_animating flag, cleared in the spring's on_finish.
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