Skip to content

improve(desktop-gpui): 23-34x faster pixelate masks in the screenshot editor - #2555

Open
FranprzDev wants to merge 3 commits into
CapSoftware:mainfrom
FranprzDev:perf/gpui-pixelate-mask-direct
Open

FranprzDev wants to merge 3 commits into
CapSoftware:mainfrom
FranprzDev:perf/gpui-pixelate-mask-direct

Conversation

@FranprzDev

@FranprzDev FranprzDev commented Oct 14, 2026 •

Copy link
Copy Markdown

What changes

cap_gpui_kernels::screenshot::mask_filter with pixelate = true (the screenshot editor's Pixelate mask, which is the type a new mask gets, at the default level 16) no longer copies the region into an RgbaImage and runs image::imageops::resize(.., FilterType::Nearest) twice (down to size / block, then back up).

It now computes, once per call, which source column and which source row every output pixel lands on after those two nearest-neighbour resizes, then fills the output straight from the frame: one 4-byte copy per pixel of a new row, and a whole-row extend_from_within for every row that repeats the previous one (all but one row per block).

The index mapping is the one image 0.25 uses for FilterType::Nearest: resize runs the box kernel with zero support through vertical_sample / horizontal_sample, which always picks the single source pixel clamp(floor((out + 0.5) * (in as f32 / out as f32)), 0, in - 1) with weight 1.0, so composing that mapping twice is byte-identical to the old output. The Blur branch (FilterType::Triangle) is unchanged.

Also adds:

  • kernels/benches/screenshot_mask.rs, a before/after bench in the style of screenshot_blit.rs: the previous implementation is kept as mod baseline, both outputs are asserted equal for every workload before timing, before/after order alternates, results are printed as CSV;
  • a unit test (pixelate_matches_two_nearest_resizes) that compares the new path with the old two-resize reference across regions at the frame edges, 1×1 regions, odd sizes and levels from 1 to 100.

Why

Every mask build in the screenshot editor runs this per mask (moving, resizing or changing the level of a mask rebuilds its overlay), and the export's mask pass runs it again over each mask's region. For a 4K screenshot the old path spent most of its time converting to and from Rgba32F intermediates and sampling pixel by pixel with get_pixel/put_pixel, even though nearest-neighbour sampling only ever copies pixels.

Impact

Median time per mask_filter(.., pixelate = true, ..) call, 3 runs × 20 measured pairs per workload (after 5 warm-up pairs each), pinned to one core, Rust 1.95.0 (the toolchain CI uses for cap-gpui-kernels), GPUI release profile settings (opt-level = 3, lto = "thin", codegen-units = 1).

Workload (frame, region, level) Before (µs) After (µs) Speedup p95 before (µs) p95 after (µs)
1080p, 400×300, 16 (default) 1220.9 43.4 28.1× 1375.9 70.2
1080p, 400×300, 4 1252.5 36.3 34.5× 1273.7 38.1
4K, 1200×800, 16 (default) 8858.9 267.7 33.1× 9017.7 315.1
4K, 1200×800, 50 8610.5 250.0 34.4× 8645.2 295.3
4K, full frame, 16 (default) 111355.0 4912.9 22.7× 115945.3 8275.3

Measured on an ARM Neoverse-V2 Linux VM (2 vCPUs); absolute numbers will differ on Apple silicon and x86, but the removed work (two float resampling passes and two intermediate Rgba32F buffers per mask) is the same on every target.

Validation

cd apps/desktop-gpui
cargo +1.95.0 test --locked -p cap-gpui-kernels
cargo +1.95.0 bench --locked -p cap-gpui-kernels --bench screenshot_mask
  • screenshot.rs unit tests pass, including the existing blit tests and the new pixelate_matches_two_nearest_resizes.
  • The bench asserts byte-for-byte equality between the previous and the new implementation for every workload before timing it.
  • cargo fmt --check and cargo clippy --all-targets -- -D warnings (1.95.0) are clean.
  • No callers or signatures change; Cargo.lock is untouched.

I ran tests, clippy and the bench on Linux in an isolated copy of the kernels crate (same sources, same image 0.25.10 as Cargo.lock), because the full GPUI workspace needs the local zed-cap checkout. I did not run the macOS app itself.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable defects were found.

Summary

Speeds up screenshot pixelation by copying sampled pixels directly and reusing repeated rows.

  • Pixelate masks now copy their sampled pixels instead of resizing twice.

Reviews (6) · Last reviewed commit: "Merge branch 'main' into perf/gpui-pixel..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

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

A member of the Team first needs to authorize it.

@FranprzDev

Copy link
Copy Markdown
Author

Performance improve by my agent btw

@FranprzDev

Copy link
Copy Markdown
Author

Local check run on the current head (fb93238, which also drops a redundant empty-region guard; the 0 × N / N × 0 regions are now covered by pixelate_matches_two_nearest_resizes).

Run on Linux arm64 with Rust 1.95.0 in an isolated copy of cap-gpui-kernels (same sources, same image 0.25.10), because the full GPUI workspace needs the local zed-cap checkout:

  • cargo fmt --check: clean
  • cargo clippy --release --all-targets -- -D warnings: clean
  • cargo test --release: 9 passed, 0 failed
  • cargo bench --bench screenshot_mask: asserts byte-identical output against the previous implementation, then times it

The bench numbers in this single run are higher than the table in the description because the VM was busier; the table (3 runs, n=60) is the one to go by.

local checks

The failing Vercel checks are "Authorization required to deploy" for cap-web / cap-status (fork PR, no Vercel access) and do not touch apps/desktop-gpui; CI is waiting on maintainer approval to run.

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks for the PR. Greptile's 5/5 was for 2477474, and new commits have landed since, so the current head hasn't been scored. We only merge once the current head is 5/5. Please comment @greptileai to request a re-review and get it back to 5/5.

@FranprzDev

Copy link
Copy Markdown
Author

@greptileai

@FranprzDev
FranprzDev force-pushed the perf/gpui-pixelate-mask-direct branch from fb93238 to f308d7d Compare October 14, 2026 18:17
@FranprzDev

Copy link
Copy Markdown
Author

@greptileai please check

@FranprzDev

Copy link
Copy Markdown
Author

@richiemcilroy Greptile is back to 5/5 on the current head (f308d7d). Ready to merge whenever you are, thanks!

@FranprzDev
FranprzDev force-pushed the perf/gpui-pixelate-mask-direct branch from f308d7d to b414ed9 Compare October 15, 2026 13:18
@FranprzDev

Copy link
Copy Markdown
Author

@greptileai please review the latest head (b414ed9), rebased onto current main.

@FranprzDev

Copy link
Copy Markdown
Author

Hi @richiemcilroy can you authorize the deploy?
Sorry for the tag.

@FranprzDev

Copy link
Copy Markdown
Author

@greptileai please review the latest head (ab9c38c), which is main merged into the branch. No code changes on our side.

This branch has not been deployed

No deployments
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