WebKitGTK 2.54 highlights

The WebKit team at Igalia is happy to announce a new release series of WebKitGTK. The main highlight of this release is a new web process compositor built on the Skia graphics library, replacing the TextureMapper-based one. Read on for the details, along with a summary of the other most noteworthy changes from the latest release cycle.

Graphics improvements

A new Skia-based compositor

This cycle brings the largest overhaul of the rendering architecture since the adoption of Skia for 2D rendering: the web process compositor now uses the Skia API instead of the venerable TextureMapper. Layers are composed into the final frame using Skia, which allows sharing a single rendering infrastructure across the whole graphics stack and enables several optimizations:

  • Tile contents are recorded into deferred display lists and replayed on the compositor thread, so painting worker threads no longer need to touch the GPU at all.
  • Batched painting groups the drawing of many layers into a single Skia call, which improves performance on pages with many layers that can be painted in the same operation.
  • Unnecessary clip operations are avoided whenever possible, keeping the batched paths effective.

Beyond raw performance, expressing compositing as Skia draw calls made several features simpler and faster: filters and masks no longer require intermediate offscreen surfaces in most cases, and CSS blend modes, which TextureMapper never implemented, now work in composited layers. And since Skia can target both OpenGL and Vulkan, the compositor no longer stands in the way of Vulkan-based rendering in the future.

The consolidation on Skia goes beyond compositing: the option to use Cairo for 2D rendering has been removed, making Skia the only 2D rendering implementation. Rendering tiles in the main thread is no longer supported either, so threaded rendering is now the only tile painting path.

Damage-aware compositing

Damage tracking has seen substantial work this cycle. The damage is the region of the view that changed since the previous frame and therefore requires repainting; Paweł Lampe’s introduction to damage propagation covers the concept in depth. Compositing itself now uses this information, and does so by default: each draw the compositor issues is restricted to the damaged rectangles, in a way that preserves the batched painting described above. A new DamageRectangleThreshold preference allows tuning the balance between damage precision and bookkeeping cost.

The performance impact

What drove the compositor rewrite was making it simpler and easier to maintain, as Carlos García Campos explained at the Web Engines Hackfest 2026; performance came later, since TextureMapper started out ahead after more than a decade of tuning. By now the optimization work has more than closed that gap. WebKitGTK shares the compositor and all of these optimizations with WPE WebKit, whose 2.54 announcement measures their cumulative effect on a Raspberry Pi 4: MotionMark scores improve by around 36%, by around 45% on the composition-focused variant of the benchmark, and all of that while keeping the GPU markedly less busy. Benchmarks understate one part of the work, though. MotionMark animates nearly the entire viewport, so there is hardly anything for damage tracking to save. Real-world content behaves differently: usually a small area of the page is changing while everything else stays still, and skipping all of that quiet area cuts the per-frame GPU work to a fraction.

Other rendering improvements

A GPU atlas is now used for batched raster image uploads, regardless of the compositor in use, and it is reused across frames when the image set does not change, avoiding needless texture allocation and pixel uploads.

Asynchronous scrolling is smoother: several synchronization issues between the main, scrolling, and compositing threads that caused glitches while scrolling have been fixed, and the scrolling thread no longer blocks the compositor to flush its state, removing input-latency stalls on pages with many layers.

More animations can now run on the compositing thread: CSS animations using the steps() and linear() timing functions no longer force main-thread animation.

Finally, the rendering mode used when hardware acceleration is not available has been reworked and unified with WPE’s: it now always uses damage information to limit repaints, produces at most one frame per vertical blank, and uses multisample anti-aliasing when available.

API changes

Multimedia improvements

Let’s start with a transition notice: the GStreamer-based WebRTC backend is being replaced with a LibWebRTC-based implementation, which is expected to be available in the next release cycle. As a consequence, WebRTC support, which in previous releases required building with experimental features enabled, is disabled in 2.54.

The rest of the multimedia work moved forward at full speed:

  • Resource usage on pages containing many videos has been improved, by stopping the pipelines of muted, invisible video elements.
  • Media capability reporting is more accurate: non-AAC mp4a codecs (MP3, AC-3, E-AC-3) are correctly reported as supported when decoders are present, xHE-AAC support is auto-detected, and Dolby AC-4 is advertised for MSE on systems that support it.
  • Video decoding limits are now respected in MediaCapabilities queries, and can be overridden with the WEBKIT_GST_VIDEO_DECODING_LIMIT environment variable.
  • Experimental support for SourceBuffer.changeType() has been added to the MSE backend, along with a fix for playback stalling at ad transitions on Twitch.

On top of this, the GStreamer backend has received a substantial amount of memory-safety and lifetime-correctness work that translates into a more stable multimedia experience.

WebXR

The OpenXR-based WebXR implementation continues to progress. The main highlight is support for the WebXR Layers API: quad, cylinder, equirect, and cube layers are now implemented, in addition to the already supported projection layers. Layers can be backed by texture arrays, and XRSession.maxRenderLayers lets content query the compositor’s layer budget.

The backend has also been decoupled from OpenGL ES through an abstract graphics binding, paving the way for a future Vulkan-based binding.

WebXR support remains a build-time option, enabled with the ENABLE_WEBXR=ON CMake option; the Layers support additionally requires ENABLE_WEBXR_LAYERS=ON.

Web Platform support

As usual, this list is not exhaustive as WebKit continuously progresses in its support for new standards. Some of the highlights for this release are:

Web content also integrates better with the desktop settings: the prefers-reduced-motion media query now follows the dedicated reduced-motion setting introduced in GNOME 50, prefers-contrast is implemented for the first time in the GTK4 port, and prefers-color-scheme now honors the dark style preference there as well.

What’s new for WebKit developers?

WebKit can now use mimalloc as its memory allocator, as an alternative to its own bmalloc. For now it is the default only on some architectures (32-bit ARM, MIPS, RISC-V, and builds supporting 64 KB memory pages); everywhere else bmalloc remains the default, and mimalloc can be enabled with the USE_MIMALLOC build option.

Logging now falls back to the standard error output when journald is not reachable, which is common in minimal containers, and the new WEBKIT_DEBUG_OUTPUT environment variable allows choosing the log destination explicitly.

Profile-guided optimization is now supported in regular CMake builds with Clang, through the ENABLE_LLVM_PROFILE_GENERATION and USE_PGO_PROFILE options.

Finally, a note for packagers: building WebKitGTK now requires Ninja, as the CMake Makefile generator is no longer supported.

Other notes

WebDriver automation now works regardless of which GTK version of WebKitGTK an application uses: the interaction events (keyboard, mouse, and wheel) are handled even when the application runs a build of WebKitGTK different from the one providing the WebDriver binary.

On the localization front, a new Kazakh translation has been added, and the Brazilian Portuguese, Georgian, Japanese, Serbian, Slovenian, and Swedish translations have been updated.

Looking forward to 2.56

The 2.56 release series will bring even more improvements, and we expect it to be released during the spring of 2027. Until then!