Greetings GNOMErs!
Last week, when I upgraded to GNOME 3.28, I was sad to notice an extremely annoying bug in Mutter/GNOME Shell: every once in a while, a micro-stuttering happened. This was in additions to another bug that was disappointing me for quite a while: the tiling/maximize/unmaximize animations were not working on Wayland too.
About the former, it may not look like the end of the world, but trust me when I say that a split-second delay every ~10s is the perceived difference of a butter smooth and a trashy experience.
Of course, this is free software, we are free people, and I have this habit of fixing up whatever is bothering me. Naturally, I decided to fix them. I decided to document my journey for people that want to try Mutter/GNOME Shell development be less scared.
Animations
I decided to start working on the animations, since there was a comment written by Jonas Ådahl to bug 780292 that was a leading clue to whatever the issue was. Time to open GNOME Builder, and clone Mutter.
Mutter + Wayland + (Mutter + Wayland + (App))
While testing these changes, I obviously needed to run Mutter and see what was happening. Since we’re talking about Wayland, I was specifically interested in seeing which messages were being sent by the application and which message Mutter was receiving.
To dump the Wayland calls made by an application, we can just use the WAYLAND_DEBUG env var, like this:
$ WAYLAND_DEBUG=1 <application>
This should dump a lot of information into the terminal. This might or might not be useful to you.
One obvious way to test changes in Mutter is to build and install Mutter system-wide, then reboot. Rebooting takes almost 5 minutes to me. Clearly not a good approach. But Mutter has a nested mode where it can run inside another Mutter session.
To run a nested Mutter Wayland session:
$ mutter –nested –wayland
If your changes are making Mutter crash, you might want to run it with GDB. But Mutter is built with Autotools, which of course makes every single thing more complicated than it should be. You’ll notice that src/mutter is not an executable, but a wrapper script. To run Mutter under GDB, do that:
$ libtool –mode=execute gdb mutter
(gdb opens)
> r –nested –wayland
This will open a window with your new raw Mutter session. To run any graphical application against this new nested Mutter, as long as the toolkit supports Wayland, run:
$ WAYLAND_DISPLAY=wayland-1 <application>
Inspecting Mutter and Wayland
This was the trickiest part to me. Mutter has some env vars to control debugging, but I could not use them properly. Either it would dump too much info, or nothing useful at all.
I then decided to go the dumb way and just add dozens of prints around the code.
If you’re aware of any better way to do that, please leave a comment!
The Issue
The root of the issue was in this function:
static void zxdg_surface_v6_set_window_geometry (struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); surface->pending->has_new_geometry = TRUE; surface->pending->new_geometry.x = x; surface->pending->new_geometry.y = y; surface->pending->new_geometry.width = width; surface->pending->new_geometry.height = height; }
Can you spot the issue here?
…
Look again.
Notice that Mutter is accepting whatever the new geometry is. It doesn’t check if the new geometry differs from the current. When the geometry doesn’t change, we should not report anything to the compositor. If the compositor is GNOME Shell, things get even worse: we go through the JS trampoline, which is slow, when could have avoided it.
Apparently, GTK reports geometry changes even when they don’t happen, e.g. when hovering whatever area of the window. Every single one of these hundreds of geometry changes that didn’t actually change per second would go though IPC to Mutter, which will mindlessly jump into the compositor’s JS trampoline just to do… nothing. Because the geometry didn’t actually changed.
This was fixed by this commit.
Stuttering
The second point that was actually freaking me out was that Mutter was waking up my discrete GPU quite often. On a PRIME system, this means the GPU is put to sleep after a few seconds without being used. Every wakeup would produce an incredibly annoying stutter.
This was only happening on Wayland.
After further investigation, I came up with this temporary fix until Mutter becomes smarter about how it should handle GPUs. This one is already merged, and will be available on the next GNOME 3.28 release!
Memory Leak
Oh, dear, the infamous memory leak… I’ll just leave this link to the GitLab comment. Go figure.
Leave a Reply