The Art of (Not) Painting Pixels

Being a compositor and a compositing window manager, the most important aspect Mutter and GNOME Shell is to paint pixels to your monitors with relevant content. A large part of this content is provided by applications themselves, but many elements still need to be rendered on top of them.

Over the past few years, Mutter’s codebase has slowly but steadily been refactored, cleaned up, reorganized, and modernized.  This includes the internal copies of Clutter and Cogl. With the beginning of the GNOME 40 development cycle, it all converged in a specially large and exciting set of changes which we’ll be talking about in this article.

Camera

At its core, Mutter inherits the rendering routines of Clutter and Cogl. Cogl itself is a layer above OpenGL / GLX / EGL / GLES, which is what it ultimately boils down to.

An interesting aspect of Clutter is that, despite seeming like a 2D toolkit, it actually renders actors in a 3D space. This is what allows effects like moving, scaling, skewing, and rotating actors.

Clutter uses a traditional perspective projection when rendering. In practice, this mimics the real world where whatever is closer appears bigger, and what’s farther appears smaller. GNOME Shell (the “stage”) itself is rendered in a well-defined position inside this 3D space: the Z-2D plane.

 

The view cone starting from the camera; the Z-near and Z-far regions (in red); and the Z-2D plane in the middle

The camera in Clutter is an immutable, implicit camera positioned at the center of the 3D world, and many of the traditional techniques used in rendering engines also apply here, such as the Z-near and Z-far planes (in the illustration above, the planes delimiting the blue region of the view).

Lights

An interesting technique that is familiar to game developers is ray casting. In our case, ray casting is used to detect which element on screen is beneath the cursor, a process known as picking.

Since times immemorial, Clutter used painting for picking. Actors would paint themselves on a frame buffer, each actor with a different color, and Clutter would read a single pixel of the resulting picture. Cogl had several optimizations to try and not send these operations to the GPU through a journaling mechanism, but due to various constraints of how Clutter worked, these optimized code paths weren’t hit very often.

With the 3.34 release, Clutter moved away from this model of picking, and started using geometric picking. Not touching the GPU while picking, and (most importantly) not downloading GPU contents, was a considerable improvement. However, it still involved quite a bit of vertex projection, a relatively heavy operation that should be avoided when possible.

With Mutter 40, we are going a step further and implementing ray-based picking.

The well established technique of raycast throws a virtual “ray of light” into the scene, and does a hit test against a list of rectangles to figure out which ones are touched by the ray.

One fundamental aspect of ray-based picking is that it can project vertices only when necessary to perform the hit test.  In best-case scenarios, it only projects a single group of vertices. In worst-case scenarios, it projects as much as it used to do. Furthermore, by using the graphene_ray_t helper, we also benefit from vectorized operations. These facts led to a measurable reduction in how much time it takes for each pick operation to be executed, and the relative percentage of the frame times it takes.

These refactorings of the pick code enabled another improvement: pick culling. Much like culling out actors when painting, we can now cull out actors when picking. Initial profiling sessions show that, together, these improvements massively reduce pick times.

Action!

While painting what you see on your screen is a fundamental aspect of GNOME Shell, figuring out what not to paint is almost as important!

The process of “culling out” elements from the rendering pipeline is an important optimization. When you hover a button inside an application, for example, it is common that the application will only redraw that specific button, and will tell Mutter which region of it needs to be updated on screen. This allows Mutter to only redraw the region of the screen that should be updated on the next frame.

We’ve written about this feature (regional clipping) before, in a previous article. However, this cycle, we introduced an important improvement on top of it: clip frusta.

Regions are transformed to 3D objects called frustum

Despite the intimidating name, the concept is familiar: much like a clipping region is a set of 2D rectangles representing which parts of the screen contents must be updated, the clip frusta is a set of 3D volumes (frustum) representing which slices of the 3D space must be updated.

These volumes are built by projecting the 2D clip regions in the 2D plane, and extending them all the way to the camera, and also all the way against the camera. They are also delimited by the Z-near and Z-far planes.

 

By representing clips in 3D space, we can avoid projecting 3D actors in 2D planes over and over, which is yet another significant optimization of the rendering process.

Thanks to Graphene, we have access to graphene_frustum_t and various routines to operate on it. This allowed us to simultaneously optimize rendering, and remove code!

Carbon-based Compositor

You may have noticed that we’ve mentioned Graphene multiple time throughout this article. Thanks to this fancy library, a set of data structures and algorithms is readily available for us to use.

In addition to frustums and rays, Graphene offers methods and data types for 2-, 3-, and 4-dimensional vectors, boxes, rectangles, triangles, and various onlyothers. Despite using various types from Graphene, only recently Mutter moved away from its own internal implementation of matrices (CoglMatrix) to graphene_matrix_t, which allowed for another 4-digit code cleanup.

What’s Next

Now that we’ve dropped many core components of Mutter, Clutter, and Cogl, in favor of their Graphene counterparts, it is possible to think about other improvements, specially in the rendering pipeline itself.

There already is preliminary work improving the painting routines to use paint nodes more extensively, porting effects to this new API, input processing improvements, and others that directly or indirectly benefit from using Graphene. Stay tuned!

Huge thanks to Jakub Steiner for providing the assets used in this article. Parts of this article were turned into documentation in Mutter’s Wiki.

The Road to Mutter & GNOME Shell 3.38

The past two months were hectic, and many changes and new features landed just in time for the 3.37.90 release. As the release freezes approached (user interface freeze, API freeze, etc), part of the queue of merge requests needed a final decision on whether or not they were ready for the upcoming GNOME 3.38 release.

These two months were also punctuated by not one, but two conference talks related to Mutter and GNOME Shell.

As this is the final development summary before the 3.38 release, we decided to change the format a bit and cover the biggest changes that happened throughout this cycle.

Split Frame Clock

Back when Clutter was an application toolkit, it only had to deal with a single frame clock. However, now being a compositor toolkit, having a single frame clock became a limiting aspect of Clutter, since each monitor is ticking at potentially different rates and times. In practice, that meant that on multi-monitor scenarios, the monitor with the slowest refresh rate would limit other monitors.

A large surgery on Mutter’s fork of Clutter implemented a new frame clock, and made each ClutterStageView create its own frame clock, and that allowed monitors not to interfere with each other.

Picture of two monitors with glxgears running at different refresh rates
Multiple clients running at different refresh rates

You can read more about it in our previous article “Splitting Up The Frame Clock.”

Compositor Bypass

Applications such as games, media players, etc, allow running in fullscreen mode. Ideally, when an application is fullscreen should be able to avoid needlessly compositing the desktop when the only visible thing is the client’s fullscreen window. This is usually called “compositor bypass”, or “fullscreen unredirect”.

During this cycle, Mutter on Wayland supports bypassing the compositor when possible. When bypassing the compositor, the window’s content is put directly on screen, without any unnecessary compositing. The results vary from hardware to hardware, but in principle this should reduce CPU and GPU usage and, consequently, improve performance.

Screencast Improvements

Another bunch of screencast improvements made its way to Mutter. Noticeably, screencasting now works correctly even when an application is bypassing the compositor, in which case Mutter directly copies the contents of the application directly to the screencast stream. Have a look:

In addition to that, window screencasting received a round of bug fixes and improvements.

At last, GNOME Shell’s built-in screen recorder was split into a separate system service, which should make recording your screen using it smoother.

Customizable App Grid

A big change in GNOME Shell will be part of GNOME 3.38, and that’s the ability to customize the app grid. This feature was a long wish, and required a substantial number of under-the-hood improvements, and other changes to support it.

It currently supports creating folders by dragging application icons over each other, moving applications from and to folders, and repositioning applications inside the grid.

Folder dialogs also received small visual improvements to match these new changes.

Despite being a feature in itself, the customizable app grid is a necessary step to unlock future design changes that we’ve been researching and investigating for some time now. Stay tuned as we release more information about it!

Calendar Menu Updates

The calendar menu received a handful of visual improvements as well. Calendar events are now displayed below the actual calendar, and sections as more visually prominent.

Screenshot of the update calendar menu
Updated calendar menu

There are more improvements for this menu queued up for the next release. Google Summer of Code student Mariana is continuing to work on grouping notifications, and we expect it to be ready for the release after next.

Parental Controls

Various components of the desktop, including GNOME Shell, Settings, and others, now optionally integrate with the parental controls service that is part of GNOME 3.38.

This allows parents, guardians, supervisors, schools, among others, to limit which applications can be accessed by a particular user.

Other Changes

The shutdown menu was split, and “Restart” is now an entry, together “Shutdown”:

Screenshot of the Power Off / Log Out menu
Power Off / Log Out menu

The layout algorithm of the app grid was rewritten, and should improve the icon arrangement on various scenarios. The number of rows and columns is now defined based on the aspect ratio of the monitor, and the available space, and the icons themselves grow and shrink accordingly.

The number of icons per page is fixed at 24 icons per page. That’s because changing the number of icons per page would potentially incur losing the customizations made to the app grid.

In addition to that, both Mutter and GNOME Shell received an influx of under-the-hood optimizations and improvements throughout the cycle, ranging from Cogl, the underlying OpenGL layer that Mutter uses internally, to Clutter and it’s layout machinery, to Mutter itself and GNOME Shell. Together, these changes bring polish and robustness, and add up for small but noticeable improvements to the experience of using GNOME on a daily basis.

Conferences

GUADEC

GUADEC is the traditional, yearly GNOME conference. During the 2020 edition of this conference, Mutter & GNOME Shell contributors and maintainers had the chance to present the also traditional “State of the Shell”, where a recap of the past 2 cycles was made:

We appreciate the efforts of the GUADEC volunteers that made this year’s edition possible online.

Linux Plumbers Conference

In the 2020 edition of the Linux Plumbers Conference (LPC), we had the opportunity to be part of the debut of the Applications Ecossystem Micro-Conference, together with the Flatpak and Plasma Mobile projects:

We highly recommend everyone to watch and appreciate all three LPC talks in this video, for they contain lots of valuable and interesting information.

Congratulations for the LPC team for providing such a great online conference.

Epilogue

This release cycle was stuffed with new features, improvements, cleanups, code refactorings, and bug fixes, and we had a great time working on it. It is exciting to see such a large number of changes be part of a release, and we are proud of the advancements that we maintainers, contributors, and independent volunteers managed to achieve.

The results of our focus on GNOME Shell and Mutter have been really pleasing, but not just to us! Here are some folks who have great thoughts about it:

“The GNOME Shell team continues its steady path of technical and user experience improvements – not an easy thing to do in a codebase with diverse uses and a long history, such as GNOME Shell / Mutter. The team also sets an example for very successful cooperation between multiple companies and the community. Well done!”

— Matthias Clasen, GTK maintainer, Red Hat

“It’s incredible how polished and mature GNOME has become. I’ve used it to convert many new users away from Mac and Windows and I’m still looking forward to the future! Thanks GNOME team!”

— James (purpleidea)

As we celebrate the imminent GNOME 3.38 release, we also look forward the release after that, and contemplate the many challenges lie ahead.

This Month in Mutter & GNOME Shell | May and June 2020

The volunteers and contributors working on Mutter and GNOME Shell have been busy in the past couple of months — so much so that we didn’t have bandwidth to write the May development report!

As a consequence, this development summary will have an above average number of changes to highlight.

GNOME Shell

Preparations for Customizable App Grid

As part of the preparations for a customizable application grid, a new layout manager was written and replaced the current icon grid code. This new layout manager is in many ways more suitable for current and future changes:

  • It follows the delegation pattern that is common to Clutter. As such, it is a layout manager, and not an UI element itself.
  • It allows more precise control over the how the grid is displayed.
  • It uses modern JavaScript practices and is, in general, a more maintainable and comprehensive code.

The most visible impact is that it now selects a row x column configuration that is closest to the aspect ratio of the display:

New layout manager on portrait mode

There are still improvements to make, especially with ultra-wide displays, but the foundation work is already there, and it will be vastly easier to fine-tune the behavior of the app grid on different scenarios.

Also as part of the preparations for a customizable application grid, the Frequent tab was removed. You can read more about the reasons for this removal in the corresponding issue.

Actor Tree Inspector

GNOME Shell’s development tool, the Looking Glass, received a handy new tab to inspect the actor tree:

Actor tree tab
The new actor tree tab in the Looking Glass

This new inspector has been useful for developing GNOME Shell, and hopefully it’ll help extension developers too.

App Folder Dialog Updates

App folder dialogs received a bunch of visual and behavioral improvements, such as covering the entire monitor, and not changing the size of the app grid itself. Take a look:

These dialogs are now paginated, and fixed to 9 app icons per page:

Paginated folder dialogs with 9 items

Like the app grid, folder dialogs now also have better support for touchpad gestures and Drag n’ Drop.

Updates to the Message List Popup

This year, GNOME Shell has a Google Summer of Code intern working on the messages dialog. As a preparation for this project, some cleanups and reorganizations of the message list popup landed. More work in this front is happening, and an influx of improvements is expected to come soon, stay tuned!

Other Changes

GNOME Shell now supports the PrefersNonDefaultGPU key of the Desktop File specification, and will set the appropriate environment variables to launch applications using a dedicated GPU when available.

An unfortunate oversight was causing the Do Not Disturb setting to be reset on startup. This bug was fixed. A potential D-Bus race condition when creating MPRIS media players was corrected. App icons do not vertically stretch in the top bar anymore. These bugfixes were backported to GNOME 3.36.

The rendered contents of labels are now cached in the GPU.

The code that deals with workspaces in GNOME Shell is old, but a large number of cleanups to it has landed (!1119, !1251, !1294, !1297, !1298, !1307, !1310, !1313, !1320, !1333), and even more is under review. These cleanups were much needed in order to improve the overall quality and maintainability of the codebase.

The Extensions app saw some improvements too. The Logout button now works correctly.

When the host system changes timezones, GNOME Shell now properly updates the timezone offsets of the “World Clocks” section of the messages popover.

Finally, the Wacom buttom mapping on-screen display received various quality-of-life improvements.

Mutter

Layout Machinery Optimizations

A few exciting optimizations and improvements to Clutter’s layout machinery landed, and they bring groundwork for future improvements as well.

The removal of allocation flags allowed skipping the allocation phase of actors whose absolute position (that is, the on-screen position after performing the linear transformation of the actor vertices) didn’t change.

While routinely profiling Mutter, it was noticed that an abnormally high number of safety type checks were happening in a rendering hot path, during the redraw cycle. Those checks were removed.

Combined, these changes are of notable significance due to how expensive it is to recalculate the layout of actors. Some of them are also required for per-CRTC frame clocks.

Rendering Pipeline Improvements

Cogl now supports setting a maximum mipmap level, in addition to the minimum one, and background set a maximum mipmap level. This avoids creating mipmaps  that won’t be used.

Last year, MetaShapedTexture was made into a ClutterContent implementation. This change was important for a multitude of reasons, and will play a special role in the future with upcoming cleanups. However, it also introduced an unforeseen regression: Clutter paints ClutterContents before running the main painting routines, and this broke the existing culling mechanism of Mutter. After some investigation, culling was fixed again.

At last, MetaShapedTexture now uses a lighter, more appropriate function to combine opaque areas of windows.

Other Changes

Mutter saw a very, very, very, very large number of code cleanups. In fact, these cleanups combined got rid of almost the entirety of deprecated code!

Mutter also received a series of improvements to its test suit. These improvements range from fixing broken tests, make CI more reliable, add more tests, reorganize the entire test suit, among other changes.

Damage tracking, especially when combined with shadow framebuffers, is now working reliably and correctly. Importing DMA buffers is more careful about failures when importing scanout buffers. Finally, a couple of small memory leaks were plugged.

This Month in Mutter & GNOME Shell | April 2020

A bit later than usual, but nonetheless here the changes that happened during April on GNOME Shell and Mutter.

GNOME Shell

The command-line extensions tool received a round of improvements, and now reports extension errors better. Switching the scale of a monitor now should update all interface elements properly on GNOME Shell. Another quality of life improvement that landed was the inclusion of ASCII alternatives in the search index, which for example allows “eteindre” match “éteindre” (French for “power off”).

GNOME Shell now integrates with the parental controls technology being developed across the GNOME stack. If there are user restrictions in place, GNOME Shell now filters the applications that are not supposed to be used by the particular user.

One important improvement that landed during April is the rewrite of GNOME Shell’s calendar daemon. This updated version should prevent a lot of heavy background processing of events. Given the extents of the improvements, this is being considered for backporting to GNOME 3.36, but the size of the changes are also considerable. Testing and validation would be appreciated.

April then ended with the release of both GNOME Shell 3.36.2 as well as 3.37.1.

Mutter

On Mutter side, we say improvements to various parts of Clutter, such as ClutterOffscreenEffect, paint nodes, ClutterActorMeta, and various gestures. All these improvements are tiny steps to a cleaner, more maintanable codebase, and thus are much welcomed.

The most prominent addition to Mutter during April was the introduction of Wayland fullscreen unredirect. This code has been under review for many months, and required coordination between different parts of the stack, to work properly. Unfortunately, because it requires a very recent version of Xwayland (1.20.8) containing the fixes necessary for it to work properly, it is not suitable for backporting.

Improvements to the screencasting code landed in preparation for further improvements to GNOME Shell’s built-in screen recorder. We hope to be able to have a single code path for capturing the screen contents, regardless of whether the consumer is the Desktop portal, or the built-in recorder.

Also an issue many users had ran into where the Super key did not work as it should when using multiple keyboard layouts in the X11 session was fixed!. A handful of other bug fixes and improvements was made for the GNOME 3.36 stable branch was also included in the 3.36.2 release in the end of the month.

Like GNOME Shell, April ended with Mutter’s 3.37.1 release as well.

This Month in Mutter & GNOME Shell | March 2020

During March, GNOME Shell and Mutter saw their 3.36.0 and 3.36.1 releases, and the beginning of the 3.38 development cycle. We’ve focused most of the development efforts  on fixing bugs before starting the new development cycle.

From the development perspective, the 3.36.0 release was fantastic, and the number of regressions relative to the massive amount of changes that happened during the last cycle was remarkably small.

GNOME Shell

GNOME Shell saw continued improvements in its new Extensions app. New APIs were added to the Shell, which allows moving the Extensions app away into its own codebase. It also allows Shell to expose fewer interfaces through D-Bus.  The Extensions app is now available on Flathub.

A number of other small bugs and crashes were fixed for 3.36.1. Notably, the blur effect now works properly with fractional scaling.

Initial 3.38 work includes an improved Bluetooth state reporting, and the usage of JavaScript promises to simplify various asynchronous operations.

Mutter

Following the 3.36.0 release, Mutter received various fixes to window streaming support. In contrast to streaming entire monitors, which was working properly, window streaming had a few quirks and misbehaviors. For 3.36.1, we’ve tracked down many issues around it and fixed them. Streaming windows is also done using DMA buffer sharing mechanisms.

On Wayland, sometimes new windows would use the wrong position to animate, leading to the zoom in animation look broken. This issue was fixed as well. Pasting images from Firefox does not freeze apps, specially Xwayland apps, anymore. We also fixed a series of bugs where Xwayland windows would show a black border when resizing.

Mutter now properly handles hardware cursors when hotplugging GPUs, and cursor hotspots now work correctly again on virtual machines. Sometimes cursors would rotate wrongly when on already rotated displays, and this was also fixed.

On the X11 front, Mutter now respects manually configured RandR panning on X11, and a bug preventing the correct monitor scale from being applied on X11 was also fixed.

Mutter now also finally respects the “middle mouse button” emulation setting exposed via GSettings.

This Month in Mutter & GNOME Shell | February 2020

As we enter the different feature freezes that come before the 3.36, development starts to wind down, and focus shifts to testing and fixing bugs. Nonetheless, this was an exciting month for Mutter & GNOME Shell! The changes that landed, just in time for the 3.36 release, range from code cleanups, new features, quality-of-life improvements, and preparations for future important features.

GNOME Shell

GNOME Shell’s CSS engine now supports auto.  The icon grid spring animation was optimized to reduce the number of relayouts, which reduces CPU usage. Another batch of cleanups, refactorings, and fixes to GNOME Shell’s SCSS files landed.

Thanks to the ongoing efforts of extending and improving Sysprof, various bottlenecks and misbehaviors were identified in GNOME Shell and Mutter, and subsequently fixed. In particular, GNOME Shell now avoids doing I/O operations in the main thread when saving notification data on disk, and the local timezone is now cached, which avoids reading the contents of /etc/localtime more than necessary. As a consequence, GNOME Shell should behave better under heavy I/O loads on the host system.

The blur effect that is used by the new lock screen received further optimizations, and should be quick enough to not have any noticeable performance impact.

Animations are now disabled on various circumstances, such as when using a software renderer, when sharing screen with VNC streams, and when asked to by remote desktop sessions.

Extensions App

GNOME Shell now ships a new app to manage extensions:

The new Extensions application

This is now the primary way for users to manage extensions. It supports globally disabling extensions, uninstalling and updating user extensions, and toggling individual extensions on or off.

Mutter

Improved Screencasting Support

For a few years, Mutter implements a D-Bus API that allows screencasting. The screencast engine is implemented on top of PipeWire, and exports a PipeWire node that can be read and consumed by other applications.

Until now, this API would download the contents of the monitor framebuffers from the GPU to the system memory, and pass it to PipeWire. However, this was highly inneficient.

PipeWire 0.3 has support to another kind of buffer: DMA buffers. This allows Mutter not to download any framebuffer contents, and instead simply pass a file descriptor (an integer) to the clients. This results in far less CPU usage when screencasting.

A deep dive into how this was implemented will be published in the future.

Stage View Changes

Mutter is based on Clutter, which was originally developed as an application toolkit. Evidently, applications have very different constraints compared to compositors. One such constraint is about how refresh rates should be handled: applications only need to target a single refresh rate, whereas compositors need to draw on different monitors that may be running with different refresh rates.

These differences translate directly on how the code is architectured. Clutter has a single frame clock driving animations, and that does not play well with the problem domain that compositors live in.

During February, a major change on how Mutter handles drawing monitors landed. This is the first step towards achieving the goal of one frame clock per monitor.

Other Improvements

A stream of fixes to culling out rendering is being landed, and it potentially cuts down unnecessary rendering on various scenarios. For example, Mutter detects more cases when windows are completely obscured by other windows, and doesn’t ask them to render themselves.

A nice improvement to how the wallpaper is rendered allows Mutter to save resources when a scale is applied to any monitor.

Various fixes to Wayland subsurfaces support landed, and some small memory leaks were plugged. Lastly, Mutter now avoids flickering when X11 windows either ask to be unredirected or not.

This Month in Mutter & GNOME Shell | December 2019 & January 2020

GNOME Shell

Unified Layout for Dialogs

One area of focus during this cycle was unifying the layout, content structure, and feel of dialogs in GNOME Shell. Many dialogs were redesigned, polished, and updated as a result of this effort:

Improved Gesture Support

The gestures to switch workspaces, and navigate through the application grid pages, were dramatically improved, and now follow the touchpad movement.

Password Peek

The password entries in GNOME Shell now support peeking passwords! Take a look:

Folders as Dialogs

A major change on how GNOME Shell handles application folders has landed this month. Instead of being displayed as popups within the application grid, folders are now displayed above it in the form of a dialog.

Miscellaneous

A new blur effect was added to GNOME Shell. It will be used by future work, such as a redesigned lock screen, among others.

Due to the VP9 encoder being too CPU-intensive, the built-in screen recorder changed back to the VP8 encoder.

As part of a code refactoring effort, the bits of StBoxLayout that deal with hiding overflowing content were moved to a new class, StViewport. This simplifies in various ways the implementation of overflowed content in GNOME Shell.

When managing the icons in the application grid, such as creating, renaming, or deleting folders, or moving app icons in and out of these folders, the icons will animate to their positions smoothly now.

GNOME Shell’s performance profiling framework was fixed and updated to also work on Wayland.

The SCSS code that is used to generate the default GNOME Shell theme was completely revamped and reorganized, making it easier to find specific theme classes. It also received a small visual update.

At last, GNOME Shell now supports NVidia GPU offloading by showing the “Launch on Discrete GPU” entry on systems with a NVidia discrete GPU available.

Mutter

More Cogl Cleanups

Cogl is the GPU rendering abstraction used by Clutter to render its contents on screen. Clutter itself is the base of Mutter and GNOME Shell, which add window management and compositing on top of Clutter.

During the past few months, there were continued efforts to cleanup and modernize Cogl by removing dead and unused code, using more modern OpenGL features, etc.

This work continued during December and January too, with more dead code saying goodbye, and more modern code being welcomed to the codebase.

Implicit Cogl API Removal

Due to historical reasons, Cogl has two major APIs: an explicit one, with properly defined types, and functions that receive the objects they should act on; and an implicit one, that is closer to the OpenGL model, and acts on an implicit state machine with the objects to be worked on.

Many parts of the Clutter, Mutter, and GNOME Shell codebases were using the implicit Cogl API. Those usages were updated, and allowed us to remove most of the implicit API from Cogl.

ClutterOffscreenEffect Improvements

ClutterOffscreenEffect is an effect applied on UI elements that allow them to be rendered in offscreen framebuffers. This allows interesting, shader-based effects to be applied to these elements, such as contrast and brightness, blur, among others.

A few bugs were found in this effect, and were ironed out. It also received some optimizations that allow the effect to release GPU memory more often.

Introduction of ClutterSeat

Clutter’s representation of input devices was designed in the X11/XI2 times, and the API was modeled after it. This change brings the internal input model closer to Wayland.

While it may sound an unimpressive change, it’s the cornerstone for an unification of the multiple input grabbing mechanisms in use by GNOME Shell.

Between other internal refactors that are now possible, it will also facilitate the introduction of an input thread in the native backend, so the pointer cursor is no longer frozen on stalls.

This will be covered in detail in a separate article.

Improve layout phase of no-layout actors

The Clutter toolkit follows the traditional rendering pipeline, composed of the layout, paint, and pick phases. The layout phase is where the elements (in Clutter terminology, “actors”) get to know their position and size; the paint phase is where these actors paint their contents on the framebuffer; and the pick phase is where Clutter figures out which actor is hovered by the pointer.

When we know beforehand that an actor is not going to move around the screen, we can tell Clutter about it, and the layout phase can be optimized to avoid some calculations. This mode is called “no-layout”.

During January, Clutter received another set of optimizations when dealing with no-layout actors. This can reduce CPU use on some specific scenarios, such as when dragging windows.

Miscellaneous

The ClutterContent interface now is better integrated in the size negotiation phase of ClutterActors, by making actors that follow their content’s sizes report their content’s geometry.

Many improvements to how Mutter tracks Wayland windows landed. Specifically, a crasher related to wl_subsurface was ironed out, a unit test framework was introduced, and a harmless runtime warning was fixed.

When dealing with multi-GPU setups, Mutter needs to share framebuffers across GPUs. There are currently three ways to do that:

  1. The secondary GPU does an accelerated copy of the primary GPU framebuffer;
  2. The primary GPU does an accelerated copy of its own contents to the secondary GPU framebuffer;
  3. A slow, non-accelerated framebuffer is created on the secondary GPU, mapped to CPU memory, and the primary GPU contents are copied to this memory;

Mutter now features an additional way to share framebuffers: the primary GPU exports a framebuffer that is imported and read directly by the secondary GPU. This method is useful with virtual secondary GPUs, such as DisplayLink docks.

This Month in Mutter & GNOME Shell | November 2019

GNOME Shell

GNOME Shell saw many improvements during November. The commit log was dominated by cleanups, but a few improvements and polishments also found their way into the code.

The authentication dialog received a batch of bugfixes, many cleanups of deprecated objects and functions landed. The top panel’s application name is now correctly sized by hiding the spinner near it.

GNOME Shell’s cache of icons and textures received a fix to invalidate properly when dealing with scaling changes. All-day events are properly displayed in the messaging menu now.

Finally, the Alt-Tab switcher now doesn’t mistakenly show an overflow indicator when the list of windows fits the screen size.

Libcroco Removal

The libcroco dependency was dropped by importing the source files into St. This is an important step in getting rid of libcroco, which is a dated CSS parsing library.

App Grid Improvements

The icon grid saw an important fix to dragging application icons. The icons were not properly being destroyed, and thus were piling up after dragging and dropping them over time. This fix was further improved to work on more situations. This set of fixes was backported to the 3.34 release.

A nice visual improvement landed on the page indicator of the icon grid.

 

System Font

GNOME Shell now respects the system font!

Mutter

For Mutter, November highlights were the introduction of regional clipping in Cogl, and big code cleanups.

Regional Clipping

When applications and GNOME Shell draw themselves, they communicate which parts of their contents changed. That information allows Mutter to submit only the changed contents to the monitor, which is an important optimization.

Example of GNOME Clocks being partially redrawn
Example of GNOME Clocks being partially redrawn. The changed parts are painted in red.

Until GNOME 3.34, Mutter would calculate the bounding rectangle between all the regions that changed:

Mutter would submit the bounding box of all updated regions (in blue). In many situations, such as the above, that would include more than necessary.

This month, Mutter received the ability to update multiple regions independently, without using the bounding rectangle. In the example, Mutter now updates only what has actually changed:

The regions that Mutter submits (in blue) now matches the regions that really changed in the first picture (in red)

This yielded a significant improvement too! Under some circumstances, this change alone can reduce the time to submit frames by up to 44%.

Shadow Buffer

In some situations, in the native backend we now use a shadow buffer to render the stage off-screen before copying the content over to the actual buffer handed over to the display panel. While this may sound counter productive, it significantly increases performance from unusable to fairly pleasant on those systems that need it.

Other Highlights

We now prevent full window redraws when using dma-buf or EGLImage buffers on Wayland (mutter!948). This fixes partial updates of windows on Wayland, which can reduce the amount of data transferred between GPUs, CPUs, and the monitor. Together with the regional clipping explained above, this should significantly help saving battery.

Many, many Clutter and Cogl cleanups (mutter!921, mutter!819, mutter!933, mutter!932) landed too. These merge requests remove deprecated functions and features that, as time passes, are an increasingly burden for maintenance, and in some cases also prevent improvements and optimizations . About 28000 lines of legacy code has been cleaned out from Mutters own Cogl and Clutter versions so far, since we entered the 3.36 development phase. Extension authors, please make sure your extensions don’t use any of the removed code.

One legacy feature that dates back to when Clutter was a separate library used to write client applications was removed (mutter!911) from Mutter’s internal copy of Clutter. Not clearing the stage doesn’t make sense on a compositor.

Xwayland games that run fullscreen and change resolution should behave better now (mutter!739).

We’ve also seen a few bug fixes landing, for example fixes to Drag n’ Drop, a couple of memory leak fixes, crash fixes including one related to hot plugging and another that sometimes occurred when running Intellij, and a bug fix avoiding stuck full screen content.

A Review of GNOME Shell & Mutter 3.34

The last GNOME release, named “Thessaloniki”, was busy for GNOME Shell and Mutter. Many changes, ranging from code cleanups to architectural changes to performance improvements to new features landed.

Let’s take a look at the major highlights for the GNOME 3.34 release.

GNOME Shell

JavaScript Updates

GNOME Shell uses GJS, the GNOME JavaScript engine, to run. With the latest updates to GJS, such as the JS60 migration, GNOME Shell saw important updates making the codebase use modern tools and code practices.

Implicit Animations

One of the most important improvements that were part of GNOME Shell 3.34 was the transition to Clutter implicit animations. So far, GNOME Shell has been using the Tweener framework, which is written completely in JavaScript and, as a consequence, required extra work to communicate the animations to Clutter.

Using the implicit animations framework provided by Clutter allows GNOME Shell to skip a lot of JavaScript → C jumps, and thus, take less resources to run animations.

CI Integration

Testing GNOME Shell with CI is slightly tricky due to it and Mutter always being in lockstep. It is common that GNOME Shell from the git master branch needs Mutter from git master as well. Finding a good way to handle that prevented CI from landing earlier, but during this cycle we crafted custom container images and wrote the necessary scripts to allow for that.

Now, when running CI, GNOME Shell is tested with Mutter in tandem. Furthermore, on Mutter side, we’ve added a CI step to build and test GNOME Shell as well, catching many errors that would otherwise take some time to be found.

New Extensions Tool

GNOME Shell 3.34 also ships a new gnome-extensions tool, making it easier to create and manage GNOME Shell extensions. Due to the automation this new tool provides, such as extension templates, bash completion, packing, and testing extensions, it should be a significant improvement for extension authors.

Accessibility

With the ongoing transition to Wayland, GNOME Shell is taking ownership of many features that required random applications have full access to windows and their contents. One area where this bad practice is recurrent is the accessibility stack.

With GNOME Shell 3.34, a big coordinated effort was put in filling the missing accessibility bits  when running a Wayland session, such as Locate Pointer, Click Assist, among others.

Folder Management

Last but not least, in GNOME Shell 3.34, it is possible to create, rename, and delete folders using Drag n’ Drop actions.

GNOME Shell 3.34 in Numbers

GNOME Shell 3.34 had 309 files changed, with 50,022 lines added and 26,924 removed. 59 merge requests were merged, and 1 was closed. 71 issues were closed by commits.

Developers with the most changesets:

| 289  | Florian Müllner               |
| 84   | Marco Trevisan (Treviño)      |
| 65   | Jonas Dreßler                 |
| 32   | Georges Basile Stavracas Neto |
| 19   | Carlos Garnacho               |
| 11   | Ray Strode                    |
| 10   | Ryuta Fujii                   |
| 9    | Kukuh Syafaat                 |
| 7    | Cosimo Cecchi                 |
| 7    | Jordi Mas                     |

Mutter

Sysprof

Sysprof is GNOME’s profiling framework, built on top of the `perf` API. With the GNOME 3.34 release, Mutter now integrates with Sysprof and is able to profile a lot of its internals.

Profiling Mutter is an important requirement to detect potential bottlenecks in the algorithms and the codebase, and have a proper understanding of how, where, and why things are the way they are.

GPU Hotplug

Mutter is now able to detect and use GPUs, usually external, that are plugged while the GNOME session is running.

KMS Transactions

In order for Mutter to support more complex hardware capabilities it needs to know how to utilize the atomic KMS kernel API. A first step in this direction was taken this cycle by implementing an internal transactional KMS API. Right now this API is backed by a non-atomic implementation, in order to make sure that we don’t break anywhere we currently fully function on, but in the future having this API will enable us to have mutter utilize more advanced hardware capabilities such as overlay planes and framebuffer modifiers. It is also a big step closer to being able to isolate KMS interaction into a dedicated thread eventually enabling low latency input device feedback once we move input processing into its own dedicated thread as well.

Improved Frame Scheduler

The algorithm that Mutter uses to schedule when to update the contents of the
monitor was fine-tuned and is now able to deliver new frames more smoothly. The new algorithm gives applications more time to draw their contents and notify Mutter about it. As a consequence, Mutter is much more likely to update frames in time for the monitor to display.

NVIDIA on Xorg frame throttling changes

Further in the past, Mutter used glxSwapBuffers() to throttle frame drawing when using the proprietary NVIDIA driver. This caused issues, as it’d block the main thread for long period of times if there was constantly new frames being scheduled. To mitigate this, Mutter developers introduced functionality imitating the GLX_INTEL_swap_event extension used by the Intel driver to make it possible for swapping buffers asynchronously, by receiving a “completion event” (swap event) later on.

This was done using NVIDIA specific GLX extensions combined with running a separate thread, where the “swap event” was generated, in contrast to when using GLX_INTEL_swap_event, where the Intel driver itself did this.

In practice, this caused issues, as it the relevant GLX extension implementation in the NVIDIA driver tended to be CPU heavy. However, due to the changes this cycle to our frame scheduling algorithm, the initial problem is now mitigated by scheduling frames in a way that we will we avoid blocking on glxSwapBuffers() for as long, meaning we could remove the CPU heavy “swap event” imitation code. This should mean less CPU usage when using the NVIDIA driver and displaying an application that continuously renders frames.

Graphene

Graphene is a library implementing complicated math functionality related to vertices, matrices, rectangles and other types usually related to 3D programming. In order to decrease maintenance burden on Mutter, which had its own set of complicated math functionality doing practically the same thing, we went and replaced most of that code, and switched to using Graphene directly. Not only did we decrease the amount of code we have to maintain, we also got all the fancy new improvements done to Graphene that we would otherwise be without!

For GNOME 3.34, all but matrices were converted to the corresponding Graphene types. That’s because Cogl and Graphene matrices have different semantics and, thus, will require more scrutiny.

XWayland on Demand

Mutter and GNOME Shell 3.34 earned the ability to run as a pure Wayland compositor, while still providing seamless compatibility with X11 by starting XWayland when required by applications. This is the culmination of much prior effort at refactoring internals and ironing out indirect X11 dependencies throughout Mutter and GNOME Shell specifically, and the GNOME session generally.

Being able to start Xwayland and other related X11 services on demand for legacy applications came out organically, and demonstrates we are no longer tied by our legacy support.

This feature is disabled by default, and can be enabled by adding ‘autostart-xwayland’ to `org.gnome.mutter experimental-features`.

Real-Time Scheduler

When running as a Wayland compositor and display server, it is important that Mutter keeps its reponsiveness all the time. However, Mutter runs as a regular user application, and is subject to starvation in various scenarios, such as intensive I/O.

Mutter 3.34 now requests real-time priority, which gives it more priority than
regular applications. This avoids stalls and stutterings when running GNOME Shell as a Wayland compositor.

This feature is disabled by default, and can be enabled by adding ‘rt-scheduler’
to `org.gnome.mutter experimental-features`.

MetaShapedTexture as a ClutterContent

MetaShapedTexture represents the visual contents of an application’s surface. It takes care of making sure the content is cropped and scaled properly, and tries to optimize drawing depending on what is opaque, and what is not.

ClutterContent, on the other hand, is Clutter’s way of defining deferred rendering instructions, also known as render nodes. This enables more efficient batching of draw calls, compared to the implicit batching implemented by the Cogl journal. This cycle we took the MetaShapedTexture, which was a ClutterActor subclass manually issuing Cogl drawing instructions, and turned into a set of fully deferred rendering instructions as defined by ClutterContent.

This not only improved batching of draw calls but greatly decreased the size of the Clutter actor tree, giving us a significant performance boost.

Here’s a quick comparison:

Graph showing that MetaShapedTexture as ClutterContent reduces frame times when many windows are open.
Turning MetaShapedTexture into a ClutterContent implementation (green bars) reduces frame times when many windows are open, compared to the previous implementation (yellow bars). Courtesy of Jonas Dreßler.

 

Mutter 3.34 in Numbers

Mutter 3.34 had 766 files changed, with 34,249 lines added and 37,268 removed. 74 issues were closed by commits.

| 122 | Jonas Ådahl                   |
| 109 | Carlos Garnacho               |
| 82  | Marco Trevisan (Treviño)      |
| 52  | Olivier Fourdan               |
| 48  | Georges Basile Stavracas Neto |
| 40  | Florian Müllner               |
| 30  | Adam Jackson                  |
| 27  | Daniel van Vugt               |
| 24  | Hans de Goede                 |
| 24  | Robert Mader                  |
| 19  | Jonas Dreßler                 |
| 16  | Niels De Graef                |
| 16  | Pekka Paalanen                |

Every shell has a story

… a wise someone once muttered while walking on a beach, as they picked up a shell lying on the sand. Indeed, every shell began somewhere, crossed a unique path with different goals and driven by different motivations. Some shells were created to optimize for mobility; some, for lightness; some, for speed; some were created to just fit whoever is using it and do their jobs efficiently. It’s statistically close to impossible to not find a suitable shell, one could argue.

So, is this a blog about muttered shell wisdom?

In some way, it actually is. It is, indeed, about Shell, and about Mutter. And even though “wisdom” is perhaps a bit of an overstatement, it is expected that whoever reads this blog doesn’t leave it less wise, so the word applies to a certain degree. Evidently, the Shell in question is composed of bits and bytes; its protection is more about the complexities of a kernel and command lines than sea predators, and the Mutter is actually more about compositing the desktop than barely audible uttering.

What Now?

For a long time, the development of Mutter and GNOME Shell was surrounded by silence. This blog is a humble attempt to bring those two critical components of the GNOME desktop to the spotlight, even if only a tiny bit more.

It would be naive to say that posts will be published in a consistent frequency, but the initial goal is monthly development reports and eventual one-shot deep dives into various bits and pieces of these two components.

So fasten your seatbelts, and enjoy the ride.