Repository navigation
perf(desktop-gpui): convert camera preview frames off the main thread - #2761
richiemcilroy wants to merge 5 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| /// `release_blur_resources` behaviour (`camera.rs:1477-1484`). | ||
| #[cfg(target_os = "macos")] | ||
| /// A camera frame and the preview settings it is converted with. | ||
| #[cfg(target_os = "macos")] |
There was a problem hiding this comment.
BlurBridge is no longer gated to macOS
High Severity
The unchanged BlurBridge declaration below this insertion loses its platform guard: the original #[cfg(target_os = "macos")] now applies to ConvertJob instead. BlurBridge still references camera_blur::BlurJob, but both the import here and the module declaration in main.rs are macOS-only. Windows and Linux builds therefore fail to resolve camera_blur. Restore a macOS guard on BlurBridge.
There was a problem hiding this comment.
Addressed in the latest commits:
BlurBridgehas its doc comment and#[cfg(target_os = "macos")]back; Windows and Linux build again.- Each
ConvertJobcarriesConvertSettings(camera preview epoch, blur mode, mirroring, rebuild counter) captured when the frame was handed off.converted_arriveddrops any result whose settings no longer match the window's current ones, so a frame converted for the previous camera, or for the blur/mirror state before a toggle, is never painted or sent to the blur worker. The next frame arrives within a frame interval. - The narrating comments on
ConvertJobandconverted_arrivedare removed; the comments on buffer ownership and timing stay.
| window: &mut Window, | ||
| cx: &mut Context<Self>, | ||
| ) { | ||
| let Some(epoch) = Feeds::global(cx).read(cx).camera_preview_epoch() else { |
There was a problem hiding this comment.
Converted results lose their originating camera epoch
Medium Severity
If conversion or result delivery is delayed across a camera switch, this check accepts an old frame whenever the replacement camera has become ready. deliver_camera_frame checked freshness before enqueueing, but neither ConvertJob nor its result preserves that epoch or timestamp. The raw path then calls set_frame, which stamps the old image with the current selection revision; the blur path likewise submits it under the new epoch, bypassing its stale-output guard. This can display the previous camera as the newly selected camera. Carry the originating epoch through conversion and reject mismatched results before painting or submitting blur work.
There was a problem hiding this comment.
Addressed in the latest commits:
BlurBridgehas its doc comment and#[cfg(target_os = "macos")]back; Windows and Linux build again.- Each
ConvertJobcarriesConvertSettings(camera preview epoch, blur mode, mirroring, rebuild counter) captured when the frame was handed off.converted_arriveddrops any result whose settings no longer match the window's current ones, so a frame converted for the previous camera, or for the blur/mirror state before a toggle, is never painted or sent to the blur worker. The next frame arrives within a frame interval. - The narrating comments on
ConvertJobandconverted_arrivedare removed; the comments on buffer ownership and timing stay.
| return; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The insertion moves the existing macOS guard onto ConvertJob, leaving BlurBridge unguarded. BlurBridge still names camera_blur::BlurJob, but camera_blur only exists on macOS. Windows and Linux builds now fail to resolve that type. Restore #[cfg(target_os = "macos")] immediately before BlurBridge.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/camera_window.rs
Line: 1503
Comment:
**Windows and Linux builds fail**
The insertion moves the existing macOS guard onto `ConvertJob`, leaving `BlurBridge` unguarded. `BlurBridge` still names `camera_blur::BlurJob`, but `camera_blur` only exists on macOS. Windows and Linux builds now fail to resolve that type. Restore `#[cfg(target_os = "macos")]` immediately before `BlurBridge`.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Addressed in the latest commits:
BlurBridgehas its doc comment and#[cfg(target_os = "macos")]back; Windows and Linux build again.- Each
ConvertJobcarriesConvertSettings(camera preview epoch, blur mode, mirroring, rebuild counter) captured when the frame was handed off.converted_arriveddrops any result whose settings no longer match the window's current ones, so a frame converted for the previous camera, or for the blur/mirror state before a toggle, is never painted or sent to the blur worker. The next frame arrives within a frame interval. - The narrating comments on
ConvertJobandconverted_arrivedare removed; the comments on buffer ownership and timing stay.
| let failures_before = self.effect_failures; | ||
| // The blur mode may have been switched off (or failed) while this | ||
| // frame was converting; follow the current state. | ||
| let blur_mode = blur_mode.filter(|_| self.active_blur_mode().is_some()); |
There was a problem hiding this comment.
If the user enables blur while a frame submitted with blur_mode: None is still converting, this filter preserves None. paint_raw then displays that unblurred frame after blur has been enabled. The old synchronous path could not cross a settings change this way. Drop results whose captured effect settings no longer match the current settings, or apply the currently selected effect before painting.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/camera_window.rs
Line: 1960
Comment:
**Blur misses queued frames**
If the user enables blur while a frame submitted with `blur_mode: None` is still converting, this filter preserves `None`. `paint_raw` then displays that unblurred frame after blur has been enabled. The old synchronous path could not cross a settings change this way. Drop results whose captured effect settings no longer match the current settings, or apply the currently selected effect before painting.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Addressed in the latest commits:
BlurBridgehas its doc comment and#[cfg(target_os = "macos")]back; Windows and Linux build again.- Each
ConvertJobcarriesConvertSettings(camera preview epoch, blur mode, mirroring, rebuild counter) captured when the frame was handed off.converted_arriveddrops any result whose settings no longer match the window's current ones, so a frame converted for the previous camera, or for the blur/mirror state before a toggle, is never painted or sent to the blur worker. The next frame arrives within a frame interval. - The narrating comments on
ConvertJobandconverted_arrivedare removed; the comments on buffer ownership and timing stay.
| /// A frame came back from the conversion thread (or the inline fallback): | ||
| /// blur or paint it, and resize the window if its dimensions changed. |
There was a problem hiding this comment.
This new comment restates what converted_arrived does. The repository guide reserves comments for non-obvious context and explicitly bans comments that narrate the code. Remove this description and the similar one above ConvertJob; keep the comments explaining timing and buffer ownership. This repository requirement must be satisfied before merging.
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/camera_window.rs
Line: 1941-1942
Comment:
**Comments repeat the code**
This new comment restates what `converted_arrived` does. The repository guide reserves comments for non-obvious context and explicitly bans comments that narrate the code. Remove this description and the similar one above `ConvertJob`; keep the comments explaining timing and buffer ownership. This repository requirement must be satisfied before merging.
**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Addressed in the latest commits:
BlurBridgehas its doc comment and#[cfg(target_os = "macos")]back; Windows and Linux build again.- Each
ConvertJobcarriesConvertSettings(camera preview epoch, blur mode, mirroring, rebuild counter) captured when the frame was handed off.converted_arriveddrops any result whose settings no longer match the window's current ones, so a frame converted for the previous camera, or for the blur/mirror state before a toggle, is never painted or sent to the blur worker. The next frame arrives within a frame interval. - The narrating comments on
ConvertJobandconverted_arrivedare removed; the comments on buffer ownership and timing stay.
|
@greptileai review |
|
@greptileai review (the macOS guard on BlurBridge and stale-setting drops landed in 598b462 and 66cf6c3 after your first pass) |
What
Every camera frame shown in the bubble went through
FrameConverter::converton the main thread. That is a synchronousVTPixelTransferSessiontransfer (420v → BGRA IOSurface), plus aVTPixelRotationSessionpass when mirrored.The work runs on the GPU scaler, but the call blocks until the hardware finishes. In a symbolized profile of a Studio recording with the camera on (signed build, M4 Max), the main thread spent 438 of 2930 samples waiting in
mach_msginsideVTPixelTransferChainDoTransfer. That is about 15% of wall time, roughly 4–5 ms of every 30 fps frame, during which the UI couldn't draw or handle input.Change
frame_arrivednow hands the frame to a dedicatedcamera-preview-convertthread (bounded(1), latest wins) and returns immediately.FrameConverter, converts the newest frame, and sends the result back over a bounded(1) channel. A send blocks while the main thread still holds the previous result, so the thread is never more than one frame ahead.converted_arriveddoes what the tail offrame_arriveddid before, unchanged: blur hand-off or raw paint, window resize on a dimension change, first-frame refresh, effect feedback.force_rebuild).Not changed here: converting to the bubble's on-screen size when blur is off. The transfer runs on the hardware scaler, so the cost was the main-thread wait, not the scaling. Smaller targets would also need cover-fit sizing and resize-aware ring rebuilds. That would be a separate, measured change.
Only
apps/desktop-gpui/src/camera_window.rschanges; no Hona-authored lines are touched.Fix the Windows and Linux build failure and the stale blur-setting path before merging.
Findings
Fix with agent prompt
Summary
Moves macOS camera preview conversion off the main thread.
richiemcilroy explicitly described raw painting after blur is switched off mid-conversion as intentional in the PR description.
Reviews (1) · Last reviewed commit: "perf(desktop-gpui): convert camera previ..." · Reviewed by Greptile