Anatomy of a Frame
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:
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.
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.
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
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.