Anatomy of a Frame

Paul Lewis Paul Lewis

I'm often asked by other developers about parts of the pixel workflow, and what fires when and why, so I figured it might be worth putting up a little reference for what's involved in shipping pixels to screen.

Caveat: this is a Blink / Chrome view of the world. Most of the main thread tasks are “shared” in some form by all vendors, like layout or style calcs, but this overall architecture may not be.

A Picture Speaks a Thousand Words

It really does, so let’s start with one of those:

The process of getting pixels to screen.

The full-fat process of getting pixels to screen.


That’s a lot of content in a small space, so let’s define things a little more. It can be helpful to have the diagram above alongside these definitions, so maybe fire that up image next to this post or, for retro-old-skool points you could, you know, print it out. Sorry. Forget I mentioned it… Sorry.

Let’s start with the processes:

  • Renderer Process. The surrounding container for a tab. It contains multiple threads that, together, are responsible for various aspects of getting your page on screen. These threads are the Compositor, Tile Worker, and Main threads.

  • GPU Process. This is the single process that serves all tabs and the surrounding browser process. As frames are committed the GPU process will upload any tiles and other data (like quad vertices and matrices) to the GPU for actually pushing pixels to screen. The GPU Process contains a single thread, called the GPU Thread that actually does the work.

Renderer Process Threads

Now let's look at the threads in the Renderer Process:

  • Compositor Thread. This is the first thread to be informed about the vsync event (which is how the OS tells the browser to make a new frame). It will also receive any input events. The compositor thread will, if it can, avoid going to the main thread and will try and convert input (like – say – scroll flings) to movement on screen. It will do this by updating layer positions and committing frames via the GPU Thread to the GPU directly. If it can’t do that because of input event handlers, or other visual work, then the Main thread will be required.

  • Main Thread. This is where the browser executes the tasks we all know and love: JavaScript, styles, layout and paint. (That will change in the future under Houdini, where we will be able to run some code in the Compositor Thread.) This thread wins the award for “most likely to cause jank”, largely because of the fact that so much runs here.

  • Compositor Tile Worker(s). One or more workers that are spawned by the Compositor Thread to handle the Rasterization tasks. We’ll talk about that a bit more in a moment.

In many ways you should consider the Compositor Thread as the “big boss”. While it doesn’t run the JavaScript, Layout, Paint or any of that, it’s the thread that is wholly responsible for initiating main thread work, and then shipping frames to screen.

If it doesn’t have to wait on input event handlers, it can ship frames while waiting for the Main thread to complete its work.

You can also imagine Service Workers and Web Workers living in this process, though I’m leaving them out to because it makes things way more complicated.

The Flow of Things

The main thread in all its glory

The main thread in all its glory.

Let’s step through the flow, from vsync to pixels, and talk about how things work out in the “full-fat” version of events. It’s worth remembering that a browser need not execute all of these steps, depending on what’s necessary. For example, if there’s no new HTML to parse, then Parse HTML won’t fire. In fact, oftentimes the best way to improve performance is simply to remove the need for parts of the flow to be fired!

It’s also worth noting those red arrows just under styles and layout that seem to point towards requestAnimationFrame. It’s perfectly possible to trigger both by accident in your code. This is called Forced Synchronous Layout (or Styles, depending), and it’s often bad for performance.

Article Source: AeroTwist

All credit goes to Paul Lewis.

This text has been copied solely for demonstrative purposes.