Skip to content

perf: damage-driven idle suppression + sync send buffer reuse - #24

Merged
rldyourmnd merged 2 commits into
mainfrom
perf/damage-idle-sync-buf
Sep 23, 2026
Merged

rldyourmnd merged 2 commits into
mainfrom
perf/damage-idle-sync-buf

Conversation

@rldyourmnd

Copy link
Copy Markdown
Contributor

Summary

  • Idle-desktop suppression: X11 capturer subscribes a DAMAGE object on the root window (NON_EMPTY, re-armed via DamageSubtract); while the screen is still, capture→convert→encode is skipped entirely (25 ms damage poll, bounded 1 s so a refresh frame still lands once a second and teardown stays prompt). A pending controls.idr keyframe request wakes the wait early. Capturer::changed() defaults to true so backends without damage tracking are unchanged.
  • Sync send path: one 256 KiB scratch buffer per stream replaces a vec![0; len] allocation per chunk.
  • Live-verified on real Xorg (:10) and Xvfb: damage object present, dirty → clean → clear_area repaint → dirty.

Test plan

  • cargo fmt --all -- --check
  • cargo build -p rds-desktop -p rds-sync --all-features
  • cargo clippy -p rds-desktop --all-targets --all-features -- -D warnings
  • cargo test --workspace --all-features — 35 targets, 0 failures
  • cargo-machete clean
  • Xvfb live capture test (damage assertions included)

Generated with Devin

rldyourmnd and others added 2 commits September 23, 2026 07:19
The producer ran the full capture→convert→encode path every cadence tick
even when nothing on screen changed. The X11 capturer now subscribes a
DAMAGE object on the root window at NON_EMPTY report level and the
producer idles between 25 ms damage polls while the screen is clean.

- Capturer::changed() defaults to true, so backends without damage
  tracking behave exactly as before.
- NON_EMPTY only fires on the empty→non-empty transition; a dirty read
  issues DamageSubtract back to empty to re-arm notification.
- The wait is bounded at 1 s: the stream still gets a periodic refresh
  frame and the producer returns to the caller's is_closed check.
- A pending keyframe request (controls.idr) wakes the wait early — a
  viewer joining or recovering from loss never waits out the cap.
- Skipped slots reset the cadence instead of counting as deadline
  misses, so the bitrate controller doesn't see phantom overload.
- Damage object is destroyed on drop; absent extension falls back to
  always-dirty. Live-verified on Xorg :10 and Xvfb: dirty → clean →
  clear_area repaint → dirty.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Every chunk alloc'd a fresh vec![0; len] — on a large manifest that's
an alloc/free per 256 KiB chunk, four streams wide. Each stream now
owns a single buffer sized to MAX_CHUNK and resizes per chunk.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@rldyourmnd
rldyourmnd merged commit 87e7aea into main Sep 23, 2026
12 checks passed
@rldyourmnd
rldyourmnd deleted the perf/damage-idle-sync-buf branch September 23, 2026 02:27
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