Repository navigation
Conversation
A box-shadow was blurred from a silhouette as large as the whole allocation, on the CPU, every time the widget changed size. For a 959x181 notification with Mint-Y's 15px shadow at 2x scale this took ~280 ms; for the notification applet's menu (1055x3748) it took 1.8 s, and Cinnamon froze for that long each time a notification arrived. Away from its corners the shadow of a plain box is the same along each edge, so blur a silhouette just big enough to hold the corners and borders, and stretch its middle row and column over the rest of the allocation when painting. The 9 slices are placed exactly where the full-size texture would have landed, so the result looks the same. Shadows built from a border image or a prerendered background, and widgets smaller than the silhouette, keep the old path. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both passes summed one pixel's taps at a time in the inner loop. The vertical pass also walked down columns, one cache line per tap. Keep the order in which each pixel's taps are added, so the output is byte for byte the same, but put the row in the inner loop: neighbouring pixels no longer wait on each other and memory is read in order. 3.4-3.9x faster with the Debian build flags (111x111 at blur 30: 28 -> 7.3 ms). Co-Authored-By: Claude Opus 5.5 <[email protected]>
st_theme_node_paint_borders() pads every corner to the largest radius. The compact silhouette used only the adjacent radii for each side, so those padded regions could overlap and change the shadow alpha. Use the largest radius on every side when sizing the silhouette. Keep fractional allocations on the original path: their silhouette is scaled into a rounded-up texture, which slicing does not reproduce exactly. Add a translucent asymmetric example to the interactive test. Validation: 27 offscreen rendering cases match the original pixels; 432 old/new blur cases match byte for byte under ASan and UBSan.
Contributor
Author
|
The Mint 22 job after the latest commit still fails before compilation, while The LMDE 7 and Mint 27 builds pass. |
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.
Cinnamon froze for up to two seconds whenever a notification arrived. A profile of the main thread during those freezes: 88% in
blur_pixels(), called fromst_theme_node_render_resources().St blurs a
box-shadowon the CPU, from a silhouette as large as the whole widget, every time the widget changes size. With Mint-Y at 2x scale (#notification { box-shadow: 0 1px 15px 4px }), a 959x181 notification popup took ~280 ms. A notification applet's menu that lists 14 old notifications is 1055x3748, and blurring its shadow took 1.8 s. Any tall menu pays the same cost the first time it opens at a new size.1. st: Blur box-shadows from a corner-sized silhouette
Away from its corners, a box's shadow is the same all along each edge. This blurs a silhouette that only just holds the corners and borders,
left + 2 * ceil(1.5 * blur) + 1 + rightpixels wide, with the analogous calculation for height. Each side includes the largest border radius, matching the padding used by the border renderer. When painting, its middle row and column are stretched over the rest of the widget. The 9 slices go exactly where_st_paint_shadow_with_opacity()would have stretched the full-size texture, so the shadow looks the same. Shadows made from a border image or a prerendered background (gradients, large corners, inset shadows), and widgets smaller than the silhouette or with fractional allocation sizes, keep the old path. This is close to what gnome-shell does inst_theme_node_prerender_shadow()/st_theme_node_paint_sliced_shadow().2. st: Run blur_pixels() along rows
The two passes summed one pixel's taps at a time in the inner loop, and the vertical pass walked down columns. Now the row is the inner loop. Each pixel's taps are still added in the same order, so the output is byte for byte the same. It runs 3.4-3.9x faster with the Debian build flags.
Testing
Same blurred textures: a standalone harness that runs the old and new
blur_pixels()on 216 cases (sizes from 1x1 to 959x181, blur 0 to 31.7, solid, random and checkerboard input) found no differing byte. Timings from the same harness:Same pixels on screen: nested Cinnamon in Xephyr with Mint-Y-Dark-Aqua over a white window, screenshots of a notification popup and of the open menu, old vs new
libst.so. The only differing pixels were in the panel (an extra window button and the clock). I ran this on master at scale 1 (first commit) and on 6.6.9 with both commits at scale 2, where the popup is 959x182 like on my desktop.Offscreen rendering against unmodified master: all 27 cases match pixel for pixel, including unequal corner radii, translucent backgrounds, borders, fractional sizes, opacity, negative spread, and inset/gradient fallbacks. A separate 432-case comparison of the old and new blur functions (including padded input strides) matches byte for byte under ASan and UBSan. The interactive box-shadow test includes the unequal-radius translucent case.
On my Cinnamon 6.6.9 desktop (Mint 22.3, 2x): before, the longest main-loop stall after each of four notifications was 1.6-2.0 s. After, it is under 0.1 s, and
blur_pixelstakes 2.4% of Cinnamon's CPU time while a notification comes and goes.Built on master the same way as #14044: master needs gtk4 >= 4.18 for the background daemon, which Mint 22.3 doesn't have, so for the test build only I made that daemon optional and kept
files/from installing into/. Neither is part of this PR.🤖 Generated with Claude Code