Skip to content

perf(linux-screen): cache screenshot swscale context - #3231

Merged
richiemcilroy merged 2 commits into
CapSoftware:mainfrom
kyzer1023:perf/screenshot-swscale-cache
Oct 25, 2026
Merged

richiemcilroy merged 2 commits into
CapSoftware:mainfrom
kyzer1023:perf/screenshot-swscale-cache

Conversation

@kyzer1023

@kyzer1023 kyzer1023 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

convert_ffmpeg_frame_to_image keeps one swscale context per thread, keyed by source pixel format and size and by the RGB24 destination size. X11Grabber is still created for a single shot and dropped, so the cache lives next to the conversion rather than on the grabber (crates/recording/src/sources/screen_capture/linux.rs is already in open PR #3145).

When width * 3 is a multiple of the 32-byte line alignment Video::alloc uses, swscale writes that tight RGB24 plane straight into the image buffer. 4K (stride 11520) and 1080p (stride 5760) take this path, so the second row pack is skipped. Widths that would be padded still scale into an ffmpeg-owned frame and pack rows, which is the same layout as before.

Why

Each X11 screenshot built a new swscale context, scaled into Video::empty, then copied every row into a tight RGB buffer. A 4K BGRZ frame is about 24 MB of RGB, and that second pack moved it again. Corner rounding (#2808) and screenshot blur (#2979) run on the RGB image after this conversion. Output pixels match the previous swscale result.

Measurement

Synthetic BGRZ → RGB24, release build, one thread. The baseline is the old conversion (new swscale context every call, then a row pack). The cached path is convert_ffmpeg_frame_to_image after 5 warmup calls. Timed runs: 30. scaler_builds_during_timed_runs=0 on both sizes, so the 30 timed calls reused the context.

cargo test -p cap-recording --release --lib bench_bgrz_screenshot_conversion -- --ignored --nocapture --test-threads=1

Hardware: Linux 6.12.94+ x86_64, KVM, Intel Xeon family 6 model 207 stepping 2, 4 vCPU at 2400 MHz. rustc 1.88.0. libswscale 8.3.100. Two process runs; the table is the second. The first 4K medians were 12.407 ms → 5.248 ms wall.

Size Baseline wall median / mean Cached wall median / mean Baseline CPU median Cached CPU median
3840×2160 12.287 ms / 12.367 ms 5.175 ms / 5.476 ms 12.288 ms 5.177 ms
1920×1080 1.673 ms / 1.683 ms 1.278 ms / 1.354 ms 1.674 ms 1.278 ms

4K median wall time is 2.37× shorter (7.11 ms less per shot). Wall and thread CPU stay within a few microseconds, so the time is on-CPU. The timed loop did not rebuild the scaler.

Test plan

  • cargo test -p cap-recording --release --lib bgrx_screenshot_reuses_scaler — BGRZ and BGRA pixels match a channel swap and the old pack path; a second call with the same format and size does not build another context; a size or format change does.
  • cargo test -p cap-recording --release --lib rounded_corners
  • cargo test -p cap-recording --release --lib rgb_
  • Ignored bench above. It also checks that the cached 4K and 1080p buffers match the old pack byte for byte before timing.
  • cargo fmt -p cap-recording -- crates/recording/src/screenshot.rs
  • cargo clippy -p cap-recording --release --lib --no-deps -- -D warnings is clean. --lib --tests still reports the existing nonminimal_bool in crates/recording/src/cursor.rs (untouched).

No overlap with open PRs #3144, #3145, #3146, #2980, #2981, #2979, #2809, #3112, #3223, #3225, #3227, or other open screenshot changes. This diff is only crates/recording/src/screenshot.rs.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

Caches the screenshot scaler per thread and skips the extra row copy when RGB rows meet the alignment requirement.

  • Screenshot conversion reuses its scaler and avoids copying aligned RGB rows.

Reviews (2) · Last reviewed commit: "test(linux-screen): assert cached screen..." · Reviewed by Greptile

Reuse one swscale context across screenshot conversions and, when the
RGB24 stride is already width*3, let swscale write that plane straight
into the image instead of packing a second buffer.
@kyzer1023

Copy link
Copy Markdown
Contributor Author

@greptileai review

@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

@kyzer1023 is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread crates/recording/src/screenshot.rs
@kyzer1023

Copy link
Copy Markdown
Contributor Author

@greptileai review

@richiemcilroy
richiemcilroy merged commit d99a8f7 into CapSoftware:main Oct 25, 2026
50 of 52 checks passed
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.

2 participants