Ready for the next generation of web content
I'm Chris Harrelson, the engineering lead for Rendering (transforming HTML and CSS to pixels) in Blink. I've been deep in the trenches of rendering performance on the web for over eight years, with a personal goal of doing whatever I can to make delivering excellent UX on the web faster, easier, and more reliable. I'm excited for us to tell you about what we've done in that time to build a new, cutting-edge Chromium rendering engine architecture. To achieve this has been an enormous labor of love, and I hope you enjoy hearing about it!
In 2021, we will largely complete the process of designing, building and shipping this architecture. Let's call it RenderingNG, since it is truly a next-generation rendering architecture that greatly outperforms what came before. RenderingNG has been in progress for at least eight years, and represents the collective work of many dedicated Chromium developers. It unlocks a huge amount of potential for the next generation of fast, fluid, reliable, responsive and interactive web content. It's also a baseline that I believe defines a new minimum standard for all web rendering engines that developers can rely on.
This blog post is the first in a series, where we'll explain what we built, why we built it, and how it works. In this first post, I'll start with:
- Our north star goal.
- The pyramid of success: principles that guide our work, and examples of those principles in practice.
- The features and capabilities that RenderingNG makes possible.
- A high-level overview of the major project components of RenderingNG.
The north star goal motivating RenderingNG is that the browser engine implementation, and the richness of its rendering APIs, should not be a limiting factor of UX on the web.
You should not need to worry about browser bugs making features unreliable, or breaking your site's rendering.
There should be no mysterious performance cliffs. And, you should not need to work around missing built-in features.
It should just work.
I believe RenderingNG is a huge step towards this north star goal. Before RenderingNG, we could (and did) add rendering features and improve performance, but struggled to make those features reliable for developers, and there were many performance cliffs. Now we have an architecture that systematically squashes many of those problems, and also unblocks advanced features that were not considered feasible before. It:
- Has rock-solid core features across different platform, device, and operating system combos.
- Has predictable and reliable performance.
- Maximizes usage of hardware capabilities (cores, GPU, screen resolution, refresh rates, low-level raster APIs).
- Performs only the work that's needed to display visible content.
- Has built-in support for common visual design, animation and interaction design patterns.
- Provides developer APIs to easily manage rendering costs.
- Provides rendering pipeline extension points for developer add-ins.
- Optimizes all content—HTML, CSS, 2D Canvas, 3D canvas, images, video, and fonts.
Comparison with other browser rendering engines
Gecko and Webkit have also implemented most of the same architectural features described in these blog posts, and in some cases even added them before Chromium. Which is great! While any one browser getting faster and more reliable is cause for celebration and has real impact, the ultimate goal is to advance the baseline for all browsers, so that developers can rely on it.
The pyramid of success
My philosophy is that success is the result of first achieving reliability, then scalable performance, and finally extensibility.
As with a real-life pyramid, each level provides a necessarily-solid foundation for the level above.
If rich and complex user experiences are to be possible at all, the first thing we need is a rock-solid platform. The core features and underpinnings must work correctly, and keep working over time. And it's just as important that those features compose well and don't have strange edge-case behavior or bugs.
For this reason, reliability is the single most important part of RenderingNG. And reliability is the result of good testing, quality feedback loops, metrics, and software design patterns.
To give a sense of how important I think reliability is, we spent most of the last eight years nailing just this part. First, we built a deep knowledge of the system—learning from bug reports where the weak points were and fixing them, bootstrapping comprehensive tests, and understanding the performance needs of sites and limitations of Chromium's performance. Then we carefully and incrementally designed and rolled out key design patterns and data structures. Only then were we ready to add truly next-generation primitives for responsive design, scalability and customization of rendering.
This is not to say that nothing was improved over that time in Chromium. In fact, the opposite is true! Those years saw a steady and sustained increase in reliability and performance as we refactored and rolled out each improvement step-by-step.
Testing and metrics
Over the past 8 years, we have added tens of thousands of unit, performance and integration tests. In addition, we have developed comprehensive metrics measuring many aspects of how Chromium's rendering behaves in local testing, in performance benchmarks, and in the wild on real sites, with real users and devices.
But no matter how great RenderingNG (or another browser's rendering engine, for that matter) is, it still won't be easy to develop for the web if there are lots of bugs or differences in behavior between browsers. To address this, we also maximize use of Web Platform Tests. Each of these tests verifies a usage pattern of the web platform that all browsers should aim to pass. We also closely monitor metrics for passing more tests over time and increasing core compatibility.
Web Platform Tests are a collaborative effort. For example, Chromium engineers have added only about 10% of the total WPT tests for features of CSS; other browser vendors, independent contributors, and spec authors contribute the rest. It takes a village to raise the interoperable web!
Good software design patterns
Reliably delivering quality software is, in turn, a whole lot easier if the code is easy to understand, and designed in a way that minimizes the likelihood of bugs. We'll have a lot more to say about RenderingNG's software design in subsequent blog posts.
Achieving great performance—across the dimensions of speed, memory, and power use— is the next most important aspect of RenderingNG. We want interactions with all web sites to be smooth and responsive, yet not sacrifice the stability of the device.
But we don't just want performance, we want scalable performance—an architecture that performs reliably well on low-end and high-end machines, and across OS platforms. I call this scaling up—taking advantage of all that the hardware device can achieve, and scaling down—maximizing efficiency and reducing demand on the system when needed.
To get there, we needed to make maximum use of caching, performance isolation, and GPU hardware acceleration. Let's consider each in turn. And to make it concrete, let's think about how each of them contributes to the performance of one extremely important interaction on web pages: scrolling.
In a dynamic, interactive UI platform such as the web, caching is the single most important way to dramatically improve performance. The most well-known kind of caching in a browser is the HTTP cache, but rendering also has many caches. The most important cache for scrolling is cached GPU textures and display lists, which allow scrolling to be extremely fast while minimizing battery drain and working well across a variety of devices.
Caching helps battery life and animation frame rate for scrolling, but even more important is that it unblocks performance isolation from the main thread.
On modern desktop computers, you never have to worry about background applications slowing down the one you're working in. That's because of preemptive multitasking, which is in turn a form of performance isolation: making sure independent tasks don't slow each other down.
A GPU makes generating pixels and drawing to the screen dramatically faster—in many cases, every pixel can be drawn in parallel with every other pixel, resulting in an enormous speed increase. A key component of RenderingNG is GPU raster and draw everywhere. This uses the GPU on all platforms, and all devices, to hyper-accelerate the rendering and animating of web content. This is especially important on low-end devices or very high-end ones, which often have a much more capable GPU than other parts of the device.
Extensibility: The right tools for the job
Once we have reliability and scalable performance, we're now ready to build on top a host of tools to help developers extend the built-in parts of HTML, CSS and Canvas, and in ways that do not sacrifice any of that hard-won performance and reliability.
The following open web APIs, championed by Chromium, were made possible by RenderingNG, and were previously considered infeasible.
All of them were developed with open specifications and collaboration with open web partners—engineers at other browsers, experts, and web developers. In subsequent blog posts, we will dive into each of these and explain how RenderingNG makes them possible.
- content-visibility: allows sites to easily avoid rendering work for offscreen content, and cache rendering for not-currently-shown single page application views.
- Container queries: allows a single component to responsively lay itself out, unblocking a whole universe of plug-and-play components (currently an experimental implementation).
- Origin isolation: allows sites to opt into more performance isolation between iframes.
- Off-main-thread paint worklets: gives developers a way to extend how elements are painted, with code that runs on the compositor thread.
In addition to explicit web APIs, RenderingNG allowed us to ship several very significant "automatic features" that benefit all sites:
- Site Isolation: puts cross-origin iframes in different CPU processes, for better security and performance isolation.
- Vulkan, D3D12, and Metal: takes advantage of lower-level APIs that use GPUs more efficiently than OpenGL.
- More composited animations: SVG, background color.
Additional upcoming features unblocked by RenderingNG that we're excited about include:
- Scroll-linked animations.
- Hidden, yet searchable and accessible DOM.
- Shared element transitions.
- Custom layout.
- Off-main-thread compositing; decoupling threading and compositing.
Key projects that make up RenderingNG
Below is a list of the key projects within RenderingNG. Subsequent blog posts will deep-dive into each of them.
Disentangles compositing from style, layout and paint, allowing much-improved reliability and predictable performance, increased throughput, and using less memory without sacrificing performance. It began in 2014 and will finish this year.
|2015||Ship display lists.|
|2017||Ship new invalidation.|
|2018||Ship property trees part 1.|
|2019||Ship property trees part 2.|
A ground-up rewrite of all layout algorithms, for greatly improved reliability and more predictable performance. It began in 2016 and is planned to finish this year.
|2019||Ship block flow.|
|2020||Ship flex, editing.|
|2021||Ship everything else.|
A systematic cleanup and refactoring of the Blink rendering engine into cleanly separated pipeline phases. This allows for better caching, higher reliability, and re-entrant or delayed-rendering features such as content-visibility and container queries. It began in 2014, and incremental improvement and has been ongoing since. It will complete in 2021.
GPU Acceleration everywhere
A long-term effort to roll out GPU rasterization, draw and animation on all platforms, all of the time. GPU acceleration provides an enormous speedup for most content, because every pixel can be processed in parallel. It is also an effective method for improving performance on low-end devices, which tend to still have a GPU. It began in 2014 and completed in 2020.
|2014||Canvas support. Shipped on opt-in content on Android.|
|2016||Ship on Mac.|
|2017||GPU is used on over 60% of Android page views.|
|2018||Ship on Windows, ChromeOS, and Android Go.|
|2019||Threaded GPU rasterization.|
|2020||Ship remaining Android content.|
Threaded scrolling, animations, and decode
A long-term effort to move all scrolling, non-layout-inducing animations, and image decoding off of the main thread. It began in 2011 and is ongoing.
|2011||Initial support for threaded scroll and animation.|
|2016||Universal overflow scrolling.|
|2017||Image decodes on compositor thread.|
|2018||Image Animations on compositor thread.|
|2020||Always composite fixed-position.|
|2021||Percentage transform animations, SVG animations.|
A centralized raster and draw process for Chromium that increases throughput, optimizes memory, and allows optimal use of hardware capabilities. It also has other benefits less visible to web developers but very visible to users, such as unblocking Site Isolation and decoupling the rendering pipeline from browser UI rendering. It began in 2016 and will complete in 2021.
|2018||OOP-R shipped on Android, Mac and Windows.|
|2019||OOP-D shipped. OOP-R shipped everywhere (except Canvas). SkiaRenderer shipped on Linux.|
|2020||SkiaRenderer shipped on Windows & Android. Vulkan shipped on Android.|
|2021||SkiaRenderer shipped on Mac (and ChromeOS soon).|
Definitions of terms in the chart above:
- Out of process display compositor. Display compositing is the same kind of activity as an OS compositor. Out of process means doing it in the Viz process instead of the web page's render process or the browser UI process.
- Out of process raster. Raster is converting display lists into pixels. Out of process means doing it in the Viz process instead of the web page's render process.
- A new display compositor implementation that can support execution on a range of different underlying GPU APIs such as Vulkan, D3D12 or Metal.
Threaded and accelerated canvas rendering
This is the project that put in place the architectural pieces that made OffscreenCanvas possible. It began in 2015 and will finish in 2021.
A long-term effort to provide efficient, reliable, and high quality video playback on the web.
|2014||Introduced a Mojo-based rendering framework.|
|2015||Shipped Project Butter and video overlays for smoother video rendering.|
|2016||Shipped unified Android and desktop decoding and rendering pipelines.|
|2017||Shipped HDR and color-corrected video rendering.|
|2018||Shipped Mojo-based video decoding pipeline.|
|2019||Shipped Surface-based video rendering pipeline.|
|2021||Shipped 4K protected content rendering support on ChromeOS.|
Definitions of terms in the chart above:
- A next-generation IPC subsystem for Chromium.
- A concept that is part of the Viz project design.
I couldn't be more excited about the rate of improvement of rendering on the web and Chromium. I expect the pace will continue to accelerate in coming years as we are able to build on top of the solid basis of RenderingNG.
Stay tuned for many more future posts that will go into a lot more detail about the new architecture, how it came to be, and how it works.
Illustrations by Una Kravets.