Skip to content

perf(desktop-gpui): blur the glass backdrop in render passes on macOS - #3512

Merged
richiemcilroy merged 4 commits into
mainfrom
perf/gpui-glass-render-pass-blur
Oct 28, 2026
Merged

richiemcilroy merged 4 commits into
mainfrom
perf/gpui-glass-render-pass-blur

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Summary

On macOS, each glass pane copied the area beneath it out of the drawable with a blit, then blurred it with MPSImageGaussianBlur, a compute pass. Measured on the Mac mini, any blit or compute pass between a frame's render passes made the window hold a block of graphics memory: in the area picker, glass cost 48 MB of graphics memory more than without it, and almost all of that disappeared when the copy and blur ran as render passes instead.

The Metal renderer (zed-glass.patch) now does both in render passes, as the Direct3D and wgpu renderers already do:

  1. A render pass copies the padded region under the pane out of the drawable into the scratch texture. Drawables are made readable (framebufferOnly = false) so a shader can read them; that costs no memory and makes the old blit from the drawable valid too.
  2. Two render passes apply an exact separable gaussian, horizontal then vertical, with edges clamped and the same radius rule as the CPU model (ceil(3 sigma), normalised weights). The pass between them is stored in half floats so the vertical pass reads it unrounded.
  3. The glass draw is unchanged.

MPSImageGaussianBlur and the MetalPerformanceShaders link are gone; nothing else used them.

Measurements

Mac mini (M-series, 1080p display), release build, glass on against glass off in the same binary, two runs per state, CPU as a share of one core, memory as the process footprint:

Picker Glass memory cost, before → after Glass CPU cost, before → after
Area +74 MB → +32 MB +1.1 → +0.8 points
Display +37 MB → +30 MB +0.3 → +0.15 points
Window +44 MB → +38 MB +0.35 → +0.25 points
Main window, settings no cost either way no cost either way

Quality

  • The macOS glass probe passes all 36 scenes. Against the CPU model, mean ΔE goes from 0.153 to 0.143.
  • Captures from the old and new blur differ by at most 3 of 255 levels in any pixel; 12 of the 36 are identical.
  • gpui_macos backdrop blur tests pass, including glass_matches_the_cpu_model and blur_flush_against_window_edge_has_no_vignette.

Test plan

  • Glass probe on the Mac mini, old and new blur compared capture by capture
  • cargo test -p gpui_macos --features runtime_shaders --lib backdrop_blur_tests
  • Footprint and CPU, glass on and off, on the Mac mini
  • Glass probe and picker smoke in CI on macOS, Windows and Linux

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; both previous findings are fixed.

Summary

The PR moves macOS glass copying and blur work into render passes and computes blur weights once per pane.

  • macOS glass blurs now copy and blur the backdrop in render passes.

Reviews (3) · Last reviewed commit: "chore(desktop-gpui): drop two comments t..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 28, 2026 2:17pm UTC

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 2 other findings in Capy.

Open in Capy

Comment on lines +848 to +854
+ for (int offset = -gaussian.radius; offset <= gaussian.radius; offset++) {
+ int2 at = clamp(center + gaussian.direction * offset, int2(0), last);
+ float weight = exp(float(offset * offset) * falloff);
+ sum += weight * source.read(uint2(at));
+ total += weight;
+ }
+ return sum / total;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Blur weights repeat per pixel

backdrop_gaussian_fragment recalculates the same weights and their total for every pixel in both passes. At sigma = 20, that means 121 exp calls per pixel per pass, even though the weights depend only on sigma. This adds GPU work as panes and blur radii grow.

Precompute the normalized weights once per blur radius and pass them to the shader. That preserves the exact blur without repeating these calculations for every pixel.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/patches/zed-glass.patch
Line: 848-854

Comment:
**Blur weights repeat per pixel**

`backdrop_gaussian_fragment` recalculates the same weights and their total for every pixel in both passes. At `sigma = 20`, that means 121 `exp` calls per pixel per pass, even though the weights depend only on `sigma`. This adds GPU work as panes and blur radii grow.

Precompute the normalized weights once per blur radius and pass them to the shader. That preserves the exact blur without repeating these calculations for every pixel.

---

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!

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

@greptileai addressed in c461899: the normalised weights are computed once per blur on the CPU and passed as fragment bytes; the shader reads them and sums symmetric taps. The Metal backdrop blur tests (including the CPU-model match) pass. Please re-review.

+ backdrop_copy_pipeline_state: metal::RenderPipelineState,
+ /// The gaussian's horizontal pass, into the half-float `backdrop_temp`.
+ backdrop_gaussian_wide_pipeline_state: metal::RenderPipelineState,
+ /// The vertical pass, into `backdrop_blurred`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Comments repeat the code

The comment on backdrop_gaussian_pipeline_state only restates which pass it holds. The comment above backdrop_pass_vertex similarly describes the triangle the code draws. AGENTS.md explicitly bans comments that narrate the code rather than explain non-obvious context. Remove these comments to satisfy the repository requirement 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/patches/zed-glass.patch
Line: 210

Comment:
**Comments repeat the code**

The comment on `backdrop_gaussian_pipeline_state` only restates which pass it holds. The comment above `backdrop_pass_vertex` similarly describes the triangle the code draws. `AGENTS.md` explicitly bans comments that narrate the code rather than explain non-obvious context. Remove these comments to satisfy the repository requirement 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!

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

View 2 other findings in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

@greptileai removed both comments in 155bf68; please re-review.

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy
richiemcilroy merged commit 5a3a0d4 into main Oct 28, 2026
59 of 60 checks passed

This branch was successfully deployed

2 active deployments
Preview – cap-web — 155bf68d Deployed Oct 28, 2026 by vercel[bot]
Preview – cap-status — 155bf68d Deployed Oct 28, 2026 by vercel[bot]
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.

1 participant