Skip to content

layout.js: paint uiGroup natively when no mapped actor is skipped - #14044

Open
rumours86 wants to merge 2 commits into
linuxmint:masterfrom
rumours86:uiactor-native-paint
Open

rumours86 wants to merge 2 commits into
linuxmint:masterfrom
rumours86:uiactor-native-paint

Conversation

@rumours86

@rumours86 rumours86 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

UiActor.vfunc_paint() calls child.paint() from JS for every child of uiGroup, including hidden tooltips and menus. Each call marshals a ClutterPaintContext; a profile with a continuously redrawing window put about 9% of Cinnamon's CPU time in gjs_value_from_g_argument alone.

Chain up to StWidget so that Clutter traverses the children natively whenever no mapped actor needs to be skipped. Unmapped actors are already ignored by ClutterActor.paint(), so they do not need to disable this path. Keep the original JS loop when a mapped skipped actor exists. uiGroup has no style, so the background part of StWidget.paint() draws nothing. Picking is unchanged.

The first version checked only whether skip_paint_actors was empty. In a longer desktop session I found 278 children, only six mapped, with two unmapped actors in the skip set; those two actors prevented the fast path on every frame. Also clear skip membership in Chrome._untrackActor(), while the actor is still alive, so subsequent paints do not call is_mapped() on a disposed wrapper.

Initial fast-path measurements, before the mapped-skip extension: muffin 192cd42, Cinnamon c3e2d34, cinnamon-desktop 6c6c48d, nested Xephyr session and a GTK window redrawing at 60 fps. Main-thread userspace instructions (perf stat -e instructions:u -t), divided by 60 frames/s, in A/B/A/B order:

run 1 run 2
baseline 1.66M 1.68M
native paint fast path 0.77M 0.77M

Validation of the extension:

  • All 64 combinations of mapped/skipped state for three children preserve the visible child sequence and choose the expected fast/fallback path in an isolated JS model.
  • A CJS/Muffin lifecycle harness using the actual UiActor and Chrome methods covers destroy, explicit untrack followed by destroy, remove followed by destroy, and reparent followed by destroy. Without skip cleanup, each case emits disposed-object criticals on subsequent paints; with cleanup, all four cases leave an empty skip set and take the native path without those criticals. The parent paint is a counter in this harness, so this tests lifetime and branch selection rather than framebuffer output.
  • The backport is exercised on Cinnamon 6.6.9 (Mint 22.3); panels, menus, tooltips, OSDs and fullscreen behavior were checked locally. The mapped-skip extension has no separate controlled performance benchmark; the table above measures the original native path.

For the original nested test build only, the background daemon was made optional because this Mint 22.3 installation lacks master's GTK >= 4.18 dependency, and the files/ installation destination was adjusted. Those build changes are not part of this PR. On the updated head (7c0c775), LMDE 7 and Mint 27 builds, Pattern Check and CodeFactor pass. Mint 22 repeats the existing failure in mk-build-deps, during build-dependency installation and before Cinnamon compilation; its log does not identify the individual unmet dependency.

UiActor.vfunc_paint() painted every child of uiGroup from JS. uiGroup has
dozens of children (62 in a default session, over 100 after a day of use),
almost all of them hidden tooltips and menus, so each frame paid one
JS -> C call per child, each marshalling the ClutterPaintContext.

When skip_paint_actors is empty - the normal case - chain up to StWidget,
whose paint lets ClutterActor walk the children natively. The JS loop is
kept for the case where some actor is skipped.

Measured on current master (muffin 192cd42, cinnamon c3e2d34, nested
Xephyr session, window animating at 60 fps), instructions of the Cinnamon
main thread per frame: 1.66M / 1.68M before, 0.77M / 0.76M after.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@rumours86
rumours86 force-pushed the uiactor-native-paint branch from 3d98b3d to 5a1756e Compare October 14, 2026 01:22
@rumours86

rumours86 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor Author

The Mint 22 job fails before compilation, while mk-build-deps installs the dependencies from debian/control. This PR inherits master's GTK >= 4.18 requirement for the background daemon, but the Mint 22.3 image provides GTK 4.14.5. Unmodified master at c3e2d34 fails at the same step. The LMDE 7 and Mint 27 builds pass.

Correction to my earlier explanation: Codespell runs with only_warn: 1 and succeeds; its typo annotations are not the cause of this failure.

Keep the native traversal available when all skipped actors are unmapped. Clear skip membership when Chrome untracks an actor so paint never queries disposed wrappers.
@rumours86 rumours86 changed the title layout.js: paint uiGroup's children natively when nothing is skipped layout.js: paint uiGroup natively when no mapped actor is skipped Oct 21, 2026
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