Skip to content

Drop the modal scrim's backdrop blur (fixes #36) - #37

Merged
perminder-klair merged 1 commit into
mainfrom
fix/36-scrim-blur-lag
Aug 14, 2026
Merged

Drop the modal scrim's backdrop blur (fixes #36)#37
perminder-klair merged 1 commit into
mainfrom
fix/36-scrim-blur-lag

Conversation

@perminder-klair

Copy link
Copy Markdown
Collaborator

Fixes #36. Reproduced on this machine too (Arch, AMD, fractional scale).

What was happening

The back panel is a <sheet>, and the SDK's modal chrome paints a full-viewport Gaussian backdrop blur behind every modal surface (emitModalSurfaceScrim, radius from tokens.blur.scrim, default 4).

On Linux that lands on the CPU. platform/linux/root.zig wires only presentGpuSurfacePixels, no GPU packet path, so every frame is rasterized by ReferenceRenderSurface. A snapshot confirms it: gpu_backend=software, gpu_present_path=pixels. The SDK's own comment on drawBlur calls it "the renderer's most expensive command, an O(kernel²) Gaussian gather per output pixel over what is usually the whole viewport".

At 1133x564 on a 1.67 desktop scale that is 1.77M pixels x a 15x15 kernel, roughly 400M weighted samples per frame. The renderer memoizes the blur, but the key hashes the destination pixels, and the spectrum visualizer animating behind the sheet at ~25Hz misses that memo almost every frame.

Evidence

Measured with native automate profile on:

present p50 present p90 input latency
panel closed 17 ms 19 ms n/a
panel open, before 16 ms 571 ms (max 1.2 s) 580 ms
panel open, after 69 ms 72 ms 74 ms

The bimodal p50/p90 before the fix is the memo hitting on quiet frames and missing whenever the backdrop moved. That is also why the reporter saw the visualizer run slower on FLAC than on MP3: what differs is how often the backdrop moves, not the decode.

The change

The design brief bans blur outright, so this was only ever painting a frosted edge that was never in the design. tokensFn now layers a house_overrides set under the station colors with blur.scrim = 0, so a station theme cannot bring it back. The translucent wash stays, so the modal still dims what is behind it.

The new test asserts the blur is off in both schemes and that the wash survives. It fails with expected 0, found 4 if the override is removed.

Verification

  • native test: 108/108 pass
  • Built with -Dautomation=true -Dtrace=off, drove the back panel open and took the numbers above
  • Screenshot of the open panel: wash intact, no visual regression

Not fixed here

With the panel open, present is still 69 ms/frame against 17 ms closed. That is the sheet's own ~135 extra draw commands being re-rasterized on the CPU every frame. I isolated the scrim wash at only ~10 ms of that, so it is the panel content itself. No retained or dirty-rect rendering exists on the Linux pixel path, so it is not fixable from the app. 74 ms is responsive, 580 ms was not. Worth an upstream request alongside docs/sdk-audio-device-request.md.

Opening the back panel on Linux cost the app its interactivity: about a
second of input latency on any press or scroll, and a visibly slower
spectrum visualizer.

The SDK's modal chrome paints a full-viewport Gaussian backdrop blur
behind every sheet, dialog and drawer (emitModalSurfaceScrim, radius from
tokens.blur.scrim, default 4). On Linux that runs on the CPU: the GTK
host wires only presentGpuSurfacePixels, no GPU packet path, so every
frame goes through ReferenceRenderSurface, whose own comment calls
drawBlur "the renderer's most expensive command, an O(kernel^2) Gaussian
gather per output pixel over what is usually the whole viewport". At
1133x564 on a 1.67 desktop scale that is 1.77M pixels times a 15x15
kernel, roughly 400M weighted samples per frame. The renderer memoizes
the result, but the key hashes the destination pixels, and the spectrum
visualizer animating behind the sheet at ~25Hz misses that memo almost
every frame.

Measured with `native automate profile on`:

  panel closed        present p50 17ms   p90 19ms
  panel open, before  present p50 16ms   p90 571ms (max 1.2s), input 580ms
  panel open, after   present p50 69ms   p90 72ms,             input 74ms

The bimodal p50/p90 before the fix is the memo hitting on quiet frames
and missing whenever the backdrop moved, which is also why the reporter
saw the visualizer run slower on FLAC than MP3. What differs is how often
the backdrop moves, not the decode.

The design brief bans blur outright, so this was only ever painting a
frosted edge that was never in the design. tokensFn now layers a
house_overrides set under the station colors with blur.scrim = 0. The
translucent wash stays, so the modal still dims what is behind it.

The test asserts no scheme can rearm the blur, and that the wash
survives.
@perminder-klair
perminder-klair merged commit acadae3 into main Aug 14, 2026
4 checks passed
@perminder-klair
perminder-klair deleted the fix/36-scrim-blur-lag branch August 14, 2026 10:48
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.

[v0.9.1 Linux] lag when scrolling and selecting back panel settings

1 participant