From 69287d90ac36cb6afaa35cb6e10a3169fa98f30e Mon Sep 17 00:00:00 2001 From: kyzer1023 Date: Wed, 14 Oct 2026 15:53:10 +0000 Subject: [PATCH] improve(desktop-gpui): write BGRA unpad through a raw pointer unpad_rgba_to_bgra was vec![0; len] then overwriting every pixel on the Linux/Windows playback path. Write through with_capacity + *mut u8 + set_len instead. spare_capacity_mut/MaybeUninit::write skips calloc but on rustc 1.88 (the Cap pin) the inner stores stay four byte moves and regress vs the zero-filled baseline. --- apps/desktop-gpui/kernels/Cargo.toml | 4 + .../kernels/benches/frame_unpad.rs | 78 +++++++++++++++++++ apps/desktop-gpui/kernels/src/frame.rs | 56 +++++++++---- 3 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 apps/desktop-gpui/kernels/benches/frame_unpad.rs diff --git a/apps/desktop-gpui/kernels/Cargo.toml b/apps/desktop-gpui/kernels/Cargo.toml index 5e6f190ea62..f57b830d166 100644 --- a/apps/desktop-gpui/kernels/Cargo.toml +++ b/apps/desktop-gpui/kernels/Cargo.toml @@ -38,3 +38,7 @@ harness = false [[bench]] name = "screenshot_alpha" harness = false + +[[bench]] +name = "frame_unpad" +harness = false diff --git a/apps/desktop-gpui/kernels/benches/frame_unpad.rs b/apps/desktop-gpui/kernels/benches/frame_unpad.rs new file mode 100644 index 00000000000..e85a9102d9e --- /dev/null +++ b/apps/desktop-gpui/kernels/benches/frame_unpad.rs @@ -0,0 +1,78 @@ +use cap_gpui_kernels::frame as candidate; +use std::{hint::black_box, time::Instant}; + +type Unpad = fn(&[u8], usize, usize, usize) -> Option>; + +fn main() { + println!("workload,sample,before_ns,after_ns"); + for (name, width, height) in [ + ("preview-1248x702", 1248usize, 702usize), + ("1080p", 1920, 1080), + ("4k", 3840, 2160), + ] { + let stride = (width * 4).next_multiple_of(256); + let src: Vec = (0..stride * height).map(|i| i as u8).collect(); + let before = baseline::unpad_rgba_to_bgra(&src, width, stride, height).unwrap(); + let after = candidate::unpad_rgba_to_bgra(&src, width, stride, height).unwrap(); + assert_eq!(before, after, "{name}"); + for sample in 0..35 { + let run = |f: Unpad| { + let start = Instant::now(); + let _ = black_box(f( + black_box(&src), + black_box(width), + black_box(stride), + black_box(height), + )); + start.elapsed().as_nanos() + }; + let (old, new) = if sample % 2 == 0 { + let old = run(baseline::unpad_rgba_to_bgra); + (old, run(candidate::unpad_rgba_to_bgra)) + } else { + let new = run(candidate::unpad_rgba_to_bgra); + (run(baseline::unpad_rgba_to_bgra), new) + }; + if sample >= 5 { + println!("{name},{},{old},{new}", sample - 5); + } + } + } +} + +// Inlined from main so before/after share one build and the same inputs. +mod baseline { + pub fn unpad_rgba_to_bgra( + data: &[u8], + width: usize, + stride: usize, + rows: usize, + ) -> Option> { + let row_bytes = width.checked_mul(4)?; + let output_len = row_bytes.checked_mul(rows)?; + if stride == 0 || stride < row_bytes || data.len() < stride.checked_mul(rows)? { + return None; + } + if output_len == 0 { + return Some(Vec::new()); + } + + let mut tight = vec![0; output_len]; + for (source, target) in data + .chunks_exact(stride) + .zip(tight.chunks_exact_mut(row_bytes)) + .take(rows) + { + for (source, target) in source[..row_bytes] + .chunks_exact(4) + .zip(target.chunks_exact_mut(4)) + { + target[0] = source[2]; + target[1] = source[1]; + target[2] = source[0]; + target[3] = source[3]; + } + } + Some(tight) + } +} diff --git a/apps/desktop-gpui/kernels/src/frame.rs b/apps/desktop-gpui/kernels/src/frame.rs index df1cc0ca8ee..a5f6cc667d9 100644 --- a/apps/desktop-gpui/kernels/src/frame.rs +++ b/apps/desktop-gpui/kernels/src/frame.rs @@ -24,21 +24,23 @@ pub fn unpad_rgba_to_bgra( return Some(Vec::new()); } - let mut tight = vec![0; output_len]; - for (source, target) in data - .chunks_exact(stride) - .zip(tight.chunks_exact_mut(row_bytes)) - .take(rows) - { - for (source, target) in source[..row_bytes] - .chunks_exact(4) - .zip(target.chunks_exact_mut(4)) - { - target[0] = source[2]; - target[1] = source[1]; - target[2] = source[0]; - target[3] = source[3]; + let mut tight = Vec::with_capacity(output_len); + let dest: *mut u8 = tight.as_mut_ptr(); + // SAFETY: dest is unused spare capacity; every output byte is written before set_len. + unsafe { + for row in 0..rows { + let src = data.as_ptr().add(row * stride); + let dst = dest.add(row * row_bytes); + for col in 0..width { + let s = src.add(col * 4); + let d = dst.add(col * 4); + *d = *s.add(2); + *d.add(1) = *s.add(1); + *d.add(2) = *s; + *d.add(3) = *s.add(3); + } } + tight.set_len(output_len); } Some(tight) } @@ -287,6 +289,32 @@ mod tests { assert_eq!(unpad_rows(&PADDED, 8, 10, 1).unwrap(), PADDED[..8].to_vec()); } + #[test] + fn unpads_wgpu_aligned_stride_without_copying_padding() { + let width = 3usize; + let height = 2usize; + let stride = 256; + let mut data = vec![99u8; stride * height]; + for row in 0..height { + for column in 0..width { + let base = row * stride + column * 4; + data[base] = 10; + data[base + 1] = 20; + data[base + 2] = 30; + data[base + 3] = 255; + } + } + let out = unpad_rgba_to_bgra(&data, width, stride, height).unwrap(); + assert_eq!( + out, + vec![ + 30, 20, 10, 255, 30, 20, 10, 255, 30, 20, 10, 255, 30, 20, 10, 255, 30, 20, 10, + 255, 30, 20, 10, 255 + ] + ); + assert!(!out.contains(&99)); + } + #[test] fn rejects_short_rows_and_zero_stride() { assert_eq!(unpad_rgba_to_bgra(&[0; 12], 4, 12, 1), None);