We have three SolidColor rects along with one Image item within one Stacking Context. Let's focus only on the Image display item for now. We start by iterating over each Display Item given to us by layout and converting the Display Item to a Primitive type. Adding an image converts the Display Item information to the ImagePrimitive. Next, we assign these Primitives to Layers, which are 1:1 to Stacking Contexts. From the display list dump, we only have one Stacking Context so we'll only have one Layer in this case. However, the wrinkle here is that we do this based on tiles. WebRender splits the screen into uniform 64x64 tiles. For each tile, we check if the Layer intersects the tile. If so, for every Primitive in the layer, we check whether a Primitive intersects the tile, and so store which Primitives exist on the tile. This makes it easier for every tile to know what it needs to actually render.

Once we have all the Primitives for each tile, we go through each tile and create the PackedPrimitive that's local to each tile. Let's assume for simplicity that device pixels are equal to CSS pixels, e.g. 1px in CSS specification means 1 physical pixel on the monitor (which doesn't always happen, but it's easier for this). For example, since this test case case is 100x50, this test case will span two 64x64 tiles horizontally and 1 tile vertically for 2 total. The PackedPrimitive has information about which tile it's assigned to which will be used later in the shader. What's critical here is that WebRender will upload the same PackedImagePrimitive N number of tiles times, with really the only difference being the tile id. In addition, it's uploading some data called st0 and st1. These are references to the top left and bottom right coordinates of the image in a Texture Atlas. A Texture Atlas is one giant image composed of other smaller images. Instead of creating a separate GPU buffer for just the image, WebRender uses one giant texture with parts of the Texture Atlas used for individual images. The vertex shader will reference these coordinates later as sampling coordinates to render the actual image from the Texture Atlas. The list of Packed Primitives that are of the same type to render are called batches.

Next, WebRender does some notetaking on what needs to be rendered and notifies the Compositor thread, which is really the main thread of the process, that we need to update the screen. ProTip: Doing GPU operations not on the main thread means you're going to have a bad time. Once the compositor is notified, WebRender finally starts doing actual graphics things with OpenGL! The biggest brain wreck for me was realizing that with GPUs, you issue commands to the GPUs but you don't know when the GPU will actually execute the commands. In reality, it means you're queuing up work to do, and it will execute sometime in the future. Second, with shaders, you map vertices to different points on a [0..1] axis and transform them onto the screen. This makes GPUs very hard to debug as you can't actually single step through your shader to see what is going on.

If you already know OpenGL, you can skim some of this section. Otherwise, WebRender first compiles all the shaders, which are unique to the PackedPrimitiveType. In our example, we have a dedicated ps_image vertex shader that gets compiled and run whenever we need to draw an image. We also set up our vertices to be two triangles that split a quad from [0,0] to [1,1]. This gets bound to the 'aPosition' Vertex Attribute, which we'll use in the vertex shader. Then we go through every batch and start issuing GL calls. For images, we'll start here. The chunk data here is the PackedPrimitiveData for each tile. Thus for each tile we'll issue a draw call, but the draw call is an instanced draw call, which is a key rendering concept for WebRender. An instanced draw call increments gl_InstanceID that is accessible in the vertex shader. This let's us draw multiple times of the same indices without issuing new draw commands to the GPU, speeding up performance. Finally, we can take a look at the image vertex shader: