Repository navigation
perf(recording): add aarch64 NEON paths for screenshot pixel packers - #3102
Merged
richiemcilroy merged 1 commit intoOct 24, 2026
Merged
Conversation
On aarch64, rgb_from_rgba and rgba_from_raw now pack 16 pixels per step with vld4q_u8 and vst3q_u8/vst4q_u8, with a scalar tail, and write into uninitialized capacity instead of a zero-filled buffer. x86_64 and other targets keep the existing SSSE3 and scalar code. Adds a std-only screenshot-pack-benchmark example comparing the old aarch64 path with the new kernels.
Contributor
|
@shubhook is attempting to deploy a commit to the Cap Software Inc Team on Vercel. A member of the Team first needs to authorize it. |
Contributor
Author
|
Note: the tests and clippy in the description ran on a standalone crate, not on cap-recording itself. I copied the packer code and the screenshot_pixel_tests module into it because cap-recording doesn't build on my Mac. The cidre build script needs Xcode.app, and I only have the Command Line Tools. CI will check the full crate once the workflows are approved. |
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
On Apple Silicon, screenshot pixel packing is 5.3x to 6.6x faster, and a real display capture is 2.5 to 4 ms quicker. Measured on an M2.
#2808 added an SSSE3 path for
rgb_from_rgbaon x86_64 and noted that Apple Silicon / aarch64 was not measured. On aarch64 both screenshot packers still ran per-pixel scalar loops on a zero-filled buffer, and release builds useopt-level = "s", so the compiler doesn't vectorize them. This PR adds NEON paths for both packers and skips the zero-fill on aarch64. x86_64 and other targets are unchanged.How it works
rgb_from_rgba:reorder_rgb_row_neonloads 16 pixels withvld4q_u8, reorders channels, and stores withvst3q_u8. Leftover pixels go through the scalar code. It handles both channel orders, so Windows on ARM gets it too.rgba_from_raw:reorder_rgba_row_neondoes the same withvld4q_u8andvst4q_u8, swapping R and B for BGRA input.pack_rows_uninitwrites rows into the spare capacity ofVec::with_capacityasMaybeUninit<u8>and callsset_lenonly after every row is written. Unwritten memory is never exposed as&mut [u8].y * bytes_per_row, so padded rows work.unsafeblocks has a SAFETY comment.#[cfg(not(target_arch = "aarch64"))]block. The scalar helpers are compiled off aarch64 or in tests only, which avoidsdead_codeon aarch64 release builds.Changes
crates/recording/src/screenshot.rs: NEON kernels,pack_rows_uninit, cfg split, and tests.crates/recording/examples/screenshot-pack-benchmark.rs(new): std-only benchmark of the old aarch64 path against the new NEON kernels in one binary.Benchmark
Apple M2, 8 GB, macOS 27.0.1, rustc 1.88.0 with
-C opt-level=s -C lto=thin -C codegen-units=1. BGRA input withbytes_per_row = width * 4 + 64. Two warmup calls, then the median of 9 single-frame calls per variant. Each call allocates its output, as the real functions do. Outputs are checked byte for byte before timing, and the benchmark exits 1 on any mismatch. Times are ms per frame.Three more runs gave 4.58x to 6.39x for RGB and 6.07x to 6.64x for RGBA. The "zeroed" column separates the two changes. Most of the gain comes from NEON, and skipping the zero-fill saves about another 25%.
Display capture
A small binary repeating the display branch of
try_fast_capture(CGDisplayCreateImage,CGImage::data(),rgb_from_rgba, timed at the same points), linked against the packer code frommainand from this branch. The main display was 2940x1912 with 11776 bytes per row. Medians of 25 captures, three runs:Packing gets about 2.4x faster in a real capture, less than in the synthetic benchmark, probably because packing pays for the first read of the CGImage's memory.
How to test
cargo run --release --example screenshot-pack-benchmark -p cap-recording, or build the file with plainrustcand the flags above, since it only usesstd.RUST_LOG=cap_recording=debugand compare theFast capture completed inline againstmain.Testing
cargo fmt --all --checkscreenshot_pixel_tests: 9 passed on aarch64 (6 existing, 3 new) and under Rosetta on x86_64, includingrgb_ssse3_matches_original_including_scalar_tail.rgb_neon_matches_scalar_including_tail,rgba_dispatch_matches_original_for_both_channel_orders,rgba_packing_rejects_undersized_input.rgb_casesgained widths 32, 33, 47, 48, 49 and 2879. Coverage includes widths 0 to 9, widths not divisible by 16, row padding of 1, 7 and 32 bytes, 1x1, 1x1080, empty input, and both channel orders.-D warningsand the workspace lints passes for aarch64 and x86_64 on macOS, Windows and Linux.Not measured
Fast capture completed inlog line from a real Cap build, and window capture (the RGBA path) end to end.CGDisplayCreateImagemay take longer with full content.

Confidence Score: 5/5
The PR appears safe to merge; no actionable issues were found.Summary
Adds aarch64 NEON paths for screenshot RGB and RGBA packing.
Static review found no actionable issues. No builds, tests, or benchmarks were run during this review.
Reviews (1) · Last reviewed commit: "perf(recording): add aarch64 NEON paths ..." · Reviewed by Greptile