Skip to content

[Linux] Desynchronize the Wayland subsurface so frames don't redraw the GTK window - #195287

Open
spydon wants to merge 2 commits into
flutter:masterfrom
spydon:linux-desync-subsurface
Open

spydon wants to merge 2 commits into
flutter:masterfrom
spydon:linux-desync-subsurface

Conversation

@spydon

@spydon spydon commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

The Wayland subsurface renderer (#191389) presents each frame to a wl_subsurface from the raster thread, but leaves the subsurface in synchronized mode, so a frame is only shown when the parent (GTK) surface is next committed. To make that happen the renderer queued a GTK redraw of the view for every frame. That repaints the whole window with cairo on the GTK thread and damages the parent surface in full, which the compositor then has to re-upload, and none of what GTK paints is visible since it is behind the subsurface.

This change desynchronizes the subsurface, so a frame is shown as soon as the raster thread commits it, and stops queuing a redraw per frame. Window and content still change size in the same compositor update: the subsurface is synchronized again from size_allocate (before FlView sends the new window metrics to the engine, so the frame rendered at the new size is held back) until GTK has committed the resized parent surface, which it does from its own after-paint handler. Views sized to their content keep the subsurface synchronized and redraw per frame as before, since their window is resized to fit each frame.

Measured with a release build of an app showing a CircularProgressIndicator in a 2560x1400 window on GNOME 50.1 (Wayland, Mesa 26.0.8 radeonsi), CPU as a percentage of one core:

app gnome-shell
master (66b3ad9) 16.4% 13.4%
this PR 3.2% 2.8%
3.47 stable, for reference 33.6% 5.9%

gnome-shell's idle baseline is 1.9%. An empty animating game (flame-engine/flame#4143) goes from 15.6% to 2.3%. A perf profile of master showed the cost as pixman_fill and cairo_fill under gdk_window_begin_draw_frame on the GTK thread, which is the per-frame repaint.

Addresses the Wayland case of #101591. The X11 renderer (FlViewRendererOpenGL) still draws frames through GTK and is unchanged by this PR.

Tests: fl_subsurface_test.cc covers the new default and fl_subsurface_set_synchronized(). The renderer's behaviour around a resize is not unit tested, as FlViewRendererSubsurface needs a Wayland display and the tests run on X11 (as for the existing renderer tests). Checked manually on GNOME: continuous animation, drag resize, maximize and restore, minimize and restore, with no warnings logged.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

…he GTK window

The subsurface renderer presents each frame to a Wayland subsurface from the
raster thread, but the subsurface was left in synchronized mode. A frame
committed to a synchronized subsurface is only shown when the parent surface
is next committed, so the renderer queued a GTK redraw of the view for every
frame. That repaints the whole window with cairo on the GTK thread and damages
the parent surface in full, which the compositor then has to re-upload. For an
app animating in a 2560x1400 window this cost about 13% of a core in the app
and another 13% in gnome-shell, with nothing drawn by GTK being visible.

Make the subsurface desynchronized, so a frame is shown as soon as the raster
thread commits it, and stop queuing a redraw per frame. The subsurface is
synchronized again only while the widget changes size: it is set in
size_allocate, before the new window metrics reach the engine, so the frame
rendered at the new size is held back until GTK commits the resized parent
surface, and it is desynchronized from the frame clock's after-paint signal
once that commit has happened. Window and content therefore still change size
in the same compositor update.

Measured with an empty animating Flutter app in a 2560x1400 window on GNOME
(Wayland): 15.6% -> 2.5% CPU in the app and 13.4% -> 2.8% in gnome-shell.

Partial fix for flutter#101591 (Wayland only; the X11 renderer is
unchanged).
@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-linux Building on or for Linux specifically a: desktop Running on desktop team-linux Owned by the Linux platform team labels Oct 25, 2026
@spydon
spydon marked this pull request as ready for review October 25, 2026 18:27
@spydon
spydon requested a review from a team as a code owner October 25, 2026 18:27

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request configures the Wayland subsurface to be desynchronized by default, allowing frames to be shown immediately and keeping the GTK thread idle during animation. It also introduces a mechanism to synchronize the subsurface with the parent surface during resizing to ensure they change size together. The review feedback identifies an issue in the SetSynchronized test where CreateSubsurface is called before mock expectations are defined, which can lead to test warnings or failures.

@robert-ancell robert-ancell left a comment

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.

Works when I test it here. I don't think I considered we could switch synchronization during resize when I first implemented the subsurface. Some style changes and it should be good to land.

@spydon

spydon commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Works when I test it here. I don't think I considered we could switch synchronization during resize when I first implemented the subsurface. Some style changes and it should be good to land.

Thanks for the review @robert-ancell, all comments should be fixed now. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop engine flutter/engine related. See also e: labels. platform-linux Building on or for Linux specifically team-linux Owned by the Linux platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants