See the BeesAndroid project for a link to the original article,

Have we ever wondered what happens when we open an H5 page, from the time our finger touches the screen to the time the page is rendered? This is an in-depth question, which can test our understanding of the entire Android browser system, including software and hardware knowledge, in-depth understanding of these can help us in the analysis of problems and design solutions, a wider and deeper look. “Pixel Point Travel WebView” will take this question as a starting point and explore in depth the various theoretical knowledge involved in the H5 rendering process.








  1. Touch feedback: The first is touch, how this touch event is passed to the App in Android.
  2. Container creation: How Android launches the WebView container to load the URL when the touch event is passed to the App. This will involve the Chromium kernel boot and other relevant knowledge.
  3. Page loading: how the WebView sends the master document request to the server and receives the master document response after it is started.
  4. Page rendering: Once the WebView receives the main document, how it parses it into a page is the most critical and complex part.

Although in simple terms, it is roughly the above four processes. But the internal implementation is quite complex, and we’ll explore it. The article is longer and can be read selectively.

Touch feedback







the_life_of_pixel_webview_01.drawio






This article




















           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       
  3:      20053      20264      12264      11228       7765       7477       7543       9172       GIC  27 Edge      arch_timer
  5:        928       1570       1080        994        483        375        505        522       GIC  80 Level     timer
  6:          0          0          0          0          0          0          0          0       GIC  81 Level     acpu osa
  7:         91          0          0          0          0          0          0          0       GIC 103 Level     acpu om_timer
  8:          0          0          0          0          0          0          0          0       GIC 104 Level     hard_timer_irq
  9:       1748          0          0          0          0          0          0          0       GIC 186 Level     ipc_irq
 10:          0          0          0          0          0          0          0          0       GIC 187 Level     ipc_sem
 39:       3803          0          0          0          0          0          0          0       GIC 152 Level     ffd73000.i2c
 40:       1890          0          0          0          0          0          0          0       GIC 113 Level     fdf0c000.i2c
 41:       2006          0          0          0          0          0          0          0       GIC 114 Level     fdf0d000.i2c
 43:        103          0          0          0          0          0          0          0       GIC 107 Level   
 48:          0          0          0          0          0          0          0          0       GIC 145 Level     pl022
 49:          0          0          0          0          0          0          0          0       GIC 112 Level     pl022
 52:     100195          0          0          0          0          0          0          0       GIC 182 Level     asp_irq_slimbus
 53:      36182      49662          0          0          0          0          0          0       GIC 169 Level     mmc0
 54:       2414          0          0          0          0          0          0          0       GIC 290 Level     gpufreq
 55:          0          0          0          0          0          0          0          0       GIC 291 Level     gpufreq
 56:       6464          0          0          0          0          0          0          0       GIC 292 Level     gpufreq
 57:       3530          0          0          0          0          0          0          0       GIC 277 Level     irq_pdp
 58:          0          0          0          0          0          0          0          0       GIC 278 Level     irq_sdp
 59:          0          0          0          0          0          0          0          0       GIC 279 Level     irq_adp
 64:         56          0          0          0          0          0          0          0       GIC 171 Level     dw-mci

Copy the code

When we learned the principles of computer before, we knew that when an interrupt occurs, the CPU will stop the current running program, save the current running state, and then jump to the corresponding interrupt handler for processing, which is generally implemented by the three-party kernel driver. Such as Android in the input drivers/input/touchscreen ektf3k. C. The driver calls its input_report_abs and other methods to record the coordinates under the touch screen, and then writes them to the /dev/inpu/event1 device file via the input module. You can view this information using the Getevent tool.

adb shell su — getevent -lt /dev/input/event1

[   78826.389007] EV_ABS       ABS_MT_TRACKING_ID   0000001f
[   78826.389038] EV_ABS       ABS_MT_PRESSURE      000000ab
[   78826.389038] EV_ABS       ABS_MT_POSITION_X    000000ab
[   78826.389068] EV_ABS       ABS_MT_POSITION_Y    0000025b
[   78826.389068] EV_ABS       ABS_MT_SLOT          00000001
[   78826.389068] EV_ABS       ABS_MT_TRACKING_ID   00000020
[   78826.389068] EV_ABS       ABS_MT_PRESSURE      000000b9
[   78826.389099] EV_ABS       ABS_MT_POSITION_X    0000019e
[   78826.389099] EV_ABS       ABS_MT_POSITION_Y    00000361
[   78826.389099] EV_SYN       SYN_REPORT           00000000
[   78826.468688] EV_ABS       ABS_MT_SLOT          00000000
[   78826.468688] EV_ABS       ABS_MT_TRACKING_ID   ffffffff
[   78826.468719] EV_ABS       ABS_MT_SLOT          00000001
[   78826.468719] EV_ABS       ABS_MT_TRACKING_ID   ffffffff
[   78826.468719] EV_SYN       SYN_REPORT           00000000
Copy the code

When the coordinates are written to the /dev/input-event1 device file, the application only needs to listen for changes in the device file to know which touches the user has made. However, this is a tedious task that is handed over to the GUI framework of each system. WindowManagerService is a window management service in the Android system. It reads the location information and distributes it to the specified App. It calls back the response listener function (onTouch). At this point, the user’s touch event is passed to the page of the App, and the onTouch method is called back to respond to the user’s touch event. To open an H5 on Android, you typically start an Activity that has a WebView inside and calls the loadUrl method to load the URL.

Container startup

As mentioned above, H5 is loaded and rendered in a WebView, and the WebView is loaded in an Activity. Therefore, an H5 container starts with two aspects:

  1. The Activity starts and creates
  2. WebView startup and creation

Note: Why do WE talk about container startup specifically? Because it is also an important part of H5 page experience. As it is Native, front-end students may not pay attention to it. And the container navigation phase is an important preloading time, where we can do a lot of things, such as:

  1. Interface preloading
  2. HTML documents are preloaded
  3. Resource preloading
  4. Create a JS Engine for navigation that executes the JS logic ahead of time, opening up the navigation preload capability to the front end.

1 Start and create an Activity

Note: This part involves more Android knowledge, students can skip the front end.

The startup flow chart of the Activity is as follows:








  • Instrumentation: Monitor the interactions between applications and the system.
  • AMS: Component management scheduling center, does nothing, but manages everything.
  • ActivityStarter: a controller that starts an Activity. It handles the effects of intents and flags on the Activity. To be specific, it can: 1. 2 Verify the validity of startup parameters. 3 Returns the int parameter, indicating whether the Activity started successfully.
  • The ActivityStackSupervisior: This class, as you can see from its name, is designed to manage the stack of tasks.
  • ActivityStack: Used to manage activities in the task stack.
  • ActivityThread: This class is used to start, switch, and schedule activities, services, and BroadcastReceivers.

Note: The ActivityStack container is designed to handle multiple Activitystacks. Earlier versions of the container had just one ActivityStack for the phone’s screen, and when the larger container was designed to handle multiple screens, We had multiple Activitystacks, and the Activitystackcontainer was introduced to manage multiple Activitystacks. The whole process mainly involves four processes:

  • The caller process is the application Launcher process if the application is launched on the desktop.
  • ActivityManagerService is the System Server process that runs System service components.
  • Zygote process, which is mainly used to fork new processes.
  • The newly started application process, which is used to host the application running process, is also the main thread of the application (the newly created process is the main thread), and handles the component life cycle, interface drawing, and other related matters.

With this understanding, the process can be summarized as follows:

  1. Click the desktop application icon, and the Launcher process sends AMS the request to start the Activity (MainActivity) as a Binder.
  2. AMS receives a start request, information such as delivery ActivityStarter processing Intent and Flag, and then to ActivityStackSupervisior/ActivityStack Activity into the stack related processes. At the same time, the Zygote process is asked to fork a new process in Socket mode.
  3. Zygote forks a new process after receiving a request to create a new process.
  4. Create the ActivityThread object in the new process, which is the main thread of the application. Start the Looper message loop in the main thread to process the creation Activity.
  5. The ActivityThread uses the ClassLoader to load the Activity, create the Activity instance, and call back the Activity’s onCreate() method. This completes the start of the Activity.

Note: Many of these functions have the Locked suffix, which means that they are synchronized, reading and writing data shared by multiple threads.

2 The WebView starts creation

If a WebView treats it as a View, its startup process is no different from any other Android View, parsing and building the View object from code or AN XML file. But we’re not talking about a simple View creation here, we’re talking about the Chromium engine (WebView implementation based on the Chromium kernel) startup process on Android. When we refer to the start process, first think about what started, the answer is of course started process & thread, which is the carrier of our code running, so the start process of Chromium can be further refined into the start process of various processes in Chromium. Android 7.0 added the developer option to enable multiple processes. Android 8.0 enables multiple processes by default. Currently only Render Process, GPU Process is still a thread of Browser Process. What is Chromium Multi-process Architecture?

Chromium is a multi-process architecture, the significance of multi-process architecture:

  • Stability: Different H5 pages run in different processes and do not interact with each other. Independent processes can also reduce the memory stress of the main process and improve the stability of the main process.
  • Security: Chromium uses double protection mechanism to implement SendBox mechanism.

Multi-process Architecture

As you can see above, Chromium has multiple processes, specifically:

There are two implementations of Chromium on Android.


  • Chrome: Each process contains multiple threads, such as Main Thread and I/O Thread. Render Process and GPU Process are implemented based on Android Service components.
  • Android WebView: Android View component, can be used in Android App, load H5.
  • Single Process: Render Process and GPU Process become Browser Process threads.
  • Multi-process: Android 7.0 added the developer option to enable multi-process. Android 8.0 enables multiple processes by default. Currently only Render Process, GPU Process is still a thread of Browser Process.

When we build a WebView instance, it will load the Chromium-related so library first, and then start Browser, Render, and other processes and the necessary components for the process to run. So the whole container starts up. The startup process is as follows:


  • Browser: The AwBrowserProcess in // Android_webView is responsible for launching the Browser, which encapsulates the BrowserStartupController in // Content /public/ Android. The process of starting Browser is actually to create a Browser Main Loop in the UI thread of App. When Chromium needs to request Browser to perform an operation in the future, it can send a Task like Browser Main Loop. Of course the Task is executed in the drawing UI thread.
  • // android_webView AwContents, which encapsulates //content/public/android ContentViewCore. Start Render differently in different versions.
    • Prior to Android O, there was a single-process architecture, which created a thread in the current App process in which the web page would be rendered. This is called the in-process Renderer.
    • After Android O comes the multi-process architecture, which creates a separate process in which web pages will be rendered. This is called an out-of-process Renderer.
  • GPU: Chromium’s GPU implementation is in the Render Thread of the App, which is created by the App itself, since Chromium doesn’t need to launch it separately. But android_webview module will start a DeferredGpuCommandService service, when the CHromium Browser and Render need to perform operation on the GPU, Will send DeferredGpuCommandService service request, DeferredGpuCommandService services through the App UI Thread will GPU to Render operation Thread of execution.

After the container is started, loadUrl can be called to load the page.

Page load

Once the WebView container is created, you can call its loadUrl method to load the page. It first asks the server for the HTML Document Document resource. The URL is parsed before the request is made, and then a network thread is started to request the HTML Document resource. As follows:

Note: As shown in the previous figure, the page navigation jump occurs within a browser. The basic logic is always the same. When we directly open an H5, it can be considered as starting from the Start URL request phase.

Divided by color, the entire page navigation loading process has three roles:

  • Yellow: Browser
  • Blue: the Network
  • Green: the Renderer
  1. BrowserInitialization: Conversion of entered keywords to the actual url. (Opening H5 directly does not have this step).
  2. BeiginNavigation: Call the BeiginNavigation function to start navigation.
  3. Start URL request: starts the URL request. Network requests are managed by NavigationURLLoader.
  4. Read Response: Reads the Response.
  5. Find Render: After receiving a response to the URL request, jump back to the browser interface and prepare to build the page.
  6. Commit: Tells the Renderer Process that the HTML document has been received and that a new page needs to be rendered.
  7. Frame has Commited Navigation: Gives the Browser Process an ACK telling it that the render request has been received. The navigation process has been completed, but the interface is still blank because it has not entered the rendering process.
  8. Load: Reads the Response of an HTML document, parses it, and renders it in the web page.
  9. Load Stop: Once the Renderer Process has rendered, it notifies the Browser Process that the page has been installed.

Compare the above with the W3C Navigation Timing.








NavigationURLLoader manages network requests. The following processes are used to initiate HTTP requests:

  1. The DNS
    1. If the browser has a cache, use the browser cache directly, otherwise use the native cache.
    2. If no, use the DNS resolution service to query the corresponding IP address.
  2. TCP connection (if HTTPS, TLS connection is required)
    • Three handshakes establish a connection
    • Four waves to disconnect
  3. Request data transfer
    • The application layer sends data requests
    • The transport layer undergoes a three-way handshake connection TCP connection
    • IP addressing is performed at the network layer
    • The data link layer encapsulates data into frames
    • The physical layer uses physical media to transport
  • Read request response
    • 2xx: The response succeeded
    • 3xx: redirection
    • 4xx: Client error
    • 5xx: Server error

There’s a lot of information on the web about this, so I’m not going to expand it.

Once you get the HTML Response, you start streaming the Response to the Renderer Process and start rendering and processing the resources. The following two things will happen:

  1. The Renderer Process renders HTML into a page that interacts with the user. It consists of two main parts:
    • Blink: page rendering, including DOM Tree, Layout, Paint, Raster, etc.
    • V8: Script parsing & execution, modifying pages, responding to events, downloading resources, etc.
  2. Download resource ests of images, JS, CSS, etc.

Page rendering

The pictures in the rendering process are from the screenshot of PPT Life of a Pixel by Chromium engineer. The rendering process of a browser is to render a web page through a rendering pipeline into pixels that are eventually exported to the screen. There are three characters involved

  • Input side: web page, which Chromium abstracts into Content.
  • Rendering pipeline: Blink is mainly responsible for DOM parsing, style layout, drawing and other operations, converting web content into drawing instructions.
  • Output: mainly responsible for the drawing instructions into pixels, display on the screen.

What is Content?

We see the concept of Content a lot in the Chromium project, so what is Content? Content is the area for rendering web Content, corresponding to AwContent in the Java layer and represented by WebContents at the bottom, as shown below:

Content is described in code by Content ::WebContents, which is created by Blink in a separate Render process. Specifically, Content corresponds to HTML, CSS, JS and image involved in front-end development, as shown below:

What is a Rendering Pipeline?

The rendering pipeline can be understood as a disassembly of the rendering process, like a factory assembly line, where the semi-finished product generated in one workshop is sent to the next workshop for further assembly. Disassembling the rendering process helps simplify the rendering process and improve rendering efficiency.

When rendering is dynamic, it will trigger rendering and update pixel points when the content changes. Like the Android rendering system, triggering rendering is also triggered by the invalidate mechanism. After triggering rendering, it is very expensive to execute the whole rendering pipeline.

  • Triggering conditions are as follows:
    • scrolling
    • zooming
    • animations
    • incremental loading
    • javascript
  • The triggering methods of each process are as follows:
    • Style: Node: : SetNeedsStyleRecalc ()
    • Layout: LayoutObject: : SetNeedsLayout ()
    • Paint: PaintInvalidator: : InvalidatePaint ()
    • RasterInvalidator::Generate()

After the rendering pipe converts the webpage into drawing instructions, it cannot directly turn the drawing instructions into pixels (raster) and display them on the screen (Window). At this time, it needs to use the ability of the operating system itself (the underlying graphics library). Most platforms follow the API standardized by OpenGL in terms of the graphical interface. DirectX on Windows, Vulcan on Android. As shown below:






















Let’s start with structure








  • Blink: The Render thread running in the Render process, which is the Chromium Blink rendering engine, mainly responsible for HTML/CSS parsing, jS interpretation execution (V8), DOM manipulation, typesetting, layer tree construction and update and other tasks.
  • Layer Compositor: the Compositor thread running in the Render process is responsible for receiving the Main Frame generated by Blink, Layer tree management, Layer scrolling, rotation and other matrix changes, Layer partitioning, rasterization, texture uploading and other tasks.
  • Display Compositor: UI thread running in the Browser process that receives the Compositor Frame generated by the Layer Compositor and outputs the final OpenGL rendering instructions to draw the web content to the target window via GL mapping operations.

It also mentioned the output Frame of each level. The Frame describes the encapsulation of the data related to the drawing content output from the lower module of the rendering line to the upper module.

  • Main Frame: Contains a description of the content of a web page, mainly in the form of drawing instructions, or understood as a vector snapshot of the entire web page at a point in time.
  • Compositor Frame: The Layer Compositor receives the Main Frame generated by Blink and converts it into an internal synthesizer structure. It is sent to the Browser and eventually to the Compositor Frame, which consists of two main parts:
    • Resource: This is an encapsulation of Texture, the Layer Compositor divides each Layer into blocks, assigns resources to each block, and arranges the rasterization task.
    • Draw Quad: This represents the Draw command (rectangle Draw command, specifying coordinates, size, transformation matrix, etc.). When the Layer Compositor receives Browser’s Draw request, it generates a Draw Quad command for each block of each Layer in the currently visible area.
  • GL Frame: Display Compositor converts each Draw Quad Draw instruction of the Compositor Frame into a GL polygon Draw instruction that maps the target window using the corresponding Texture of the Resource wrapper. The set of GL drawing instructions constitutes a GL Frame, and finally the GPU executes these GL instructions to complete the drawing of the web page in the visible area of the window.

The scheduling of the entire rendering pipeline is based on requests and state machine responses. The scheduling hub runs in the Browser UI thread, which sends requests to the Layer Compositor to output the next frame according to the VSync signal of the display. The Layer Compositor determines whether to Blink the next frame according to the state of its state machine. The Layer Compositor and Display Compositor are producers and consumers. The Display Compositor holds a Compositor Frame queue that is constantly drawn and removed. The output frequency depends on the input Frame rate of the Compositor Frame and the drawing frequency of its own GL Frame. Let’s talk about the process

  1. Parse/DOM: Content is parsed into a DOM tree, which is the basis for subsequent rendering processes.
  2. Style: Parses and applies the Style sheet.
  3. -Leonard: Layout.
  4. Compositing Update: Split the entire page into separate layers according to certain rules for isolated updates.
  5. Prepaint: Builds a property tree so that a node (transform, crop, effect, scroll) can be manipulated independently without affecting its children.
  6. Paint: Paint. Verbs can mean paint, etc. Paint transforms a Layout Object in a Layout Tree into a drawing instruction (for example, draw a rectangle, draw a font, draw a color, which is a bit like calling a drawing API). These operations are then encapsulated in Dsipaly items, so the Display items are like paint, and it hasn’t really started to Draw yet.
  7. Commit: Commit copies the paint data to the synthesizer thread.
  8. Tiling: After raster receives the paint instructions, he blocks the layers first. The diagram block is the basic working unit of Raster.
  9. Raster: Rasterization.
  10. Activate: Rasterization is an asynchronous process, so the Layer Tree is divided into a Pending Tree (rasterizing the Layer that receives the Commit) and an Activate Tree (drawing the rasterized Layer from the Pending Tree). The process of copying a Layer from a Pending Tree to an Activate Tree is called Activate.
  11. The Draw: After the blocks are rasterized, the synthesizer thread generates draw Quads for each block. These Draw Quads are encapsulated into a Compositor Frame and output to the GPU. The DRAW operation is the process of generating Draw Quads.
  12. Display: After generating the Compositor Frame, Viz calls the GL command to output draw Quads to the screen.

Let’s look at the specific process.

Blink

01 Parse

The related documents

  • The DOM standard

Related to the source code

  • /blink/renderer/core/dom

When you download an HTML document from a server, the first step is parsing. The HTML parser takes in tags and streams of text (HTML is plain text) and parses the HTML document into a DOM tree. The DOM (Document Object Model), the internal representation of the DOM and the page, also exposes apis for JavaScript (V8 DOM API), allowing JavaScript programs to change the structure, style, and content of a Document. It is a tree structure, and we will see many more trees (layout trees, attribute trees, etc.) later in the rendering process because they are based on the DOM tree structure (HTML structure).


Note: HTML documents may contain multiple DOM trees, often referred to as Shadow trees, because HTML supports custom elements.

The process for parsing HTML to generate a DOM tree is as follows:

  1. HTMLDocumentParser parses tokens in HTML and generates an object model.
  2. HTMLTreeBuilder is responsible for generating a complete DOM tree. The same HTML document can contain multiple DOM trees. Custom Element elements have a shadow tree. Nodes passed in shadow Tree Slot will be found by FlatTreeTraversal traversal down.

The DOM Tree is used as the basis for the subsequent drawing process, and various types of trees are produced based on it. Specifically, the following transformations are performed:

Object conversion

  • DOM Tree -> Render Tree -> Layer Tree
  • DOM node -> RenderObject -> RenderLayer

DOM Tree (node is DOM node)

When an HTML is loaded, it is parsed to generate a DOM tree. Each node in the DOM tree corresponds to each element in the page, and the page can manipulate the DOM tree through JavaScript.

How Webkit Works

Render Tree (node is RenderObject)

However, the DOM Tree itself is not directly used for layout and rendering, so the kernel generates the Render Tree, which is a combination of THE DOM Tree and CSS, and the nodes of the two are almost one-to-one. Render Tree is a bridge between a typography engine and a rendering engine.

How Webkit Works

Layer Tree (node is RenderLayer)

Render engine is not directly using Render Tree for rendering, in order to more convenient processing operations such as positioning, clipping, industry scrolling, rendering engine will generate a Layer Tree. The rendering engine generates a RenderLayer for a particular RenderObject, but the child node of the RenderObject does not have a corresponding RenderLayer, so it is subordinate to the parent node’s RenderLayer. The rendering engine iterates through each RenderLayer, iterates through the RenderObjects that belong to that RenderLayer, and draws each RenderObject.

The Layer Tree determines the order in which the page is drawn, and the RenderObject that is subordinate to the RenderLayer determines what is drawn at that Layer.

What RenderObject is going to be the RenderLayer. GPU Accelerated Compositing in Chrome

  • It’s the root object for the page
  • It has explicit CSS position properties (relative, absolute or a transform)
  • It is transparent
  • Has overflow, an alpha mask or reflection
  • Has a CSS filter
  • Corresponds to element that has a 3D (WebGL) context or an accelerated 2D context
  • Corresponds to a element

It doesn’t matter if you don’t know the above process, we will explain them all below.

02 Style

Once the DOM tree is generated, you need to set a style for each element, either to affect only one node, or to affect the rendering of the entire DOM subtree below the entire node (for example, the rotation transformation of the node).








Related to the source code

  • /blink/renderer/core/css

Styles are usually the result of a combination of style renderers, which have complex priority semantics and a rendering process. The whole process is divided into three steps: 1. Collect, partition, and index all style rules in the style sheet.


















Access each DOM element and find all the rules that apply to that element.
















3 Combine these rules with other information (the style engine consists of partial default styles) to generate the final computed style.


03 Layout

Once you have calculated and applied the style of each DOM node, you need to decide where to place each DOM node. DOM nodes are placed based on a box model (a rectangle), and the layout is the calculation of the coordinates of those boxes.






CSS box model

|-------------------------------------------------| | | | margin-top | | | | |---------------------------------------| |  | | | | | | border-top | | | | | | | | |--------------------------|--| | | | | | | | | | | | | padding-top |##| | | | |  | |##| | | | | | |----------------| |##| | | | | | | | | | | | | ML | BL | PL | content box | PR |SW| BR | MR | | | | |  | | | | | | | | |----------------| | | | | | | | | | | | | | | padding-bottom | | | | | | | | | | | | | |--------------------------|--| | | | | | scrollbar height ####|SC| | | | | |-----------------------------| | | | | | | | | border-bottom | | | | | | | |---------------------------------------| | | | | margin-bottom | | | |-------------------------------------------------|Copy the code

The related documents

  • Blink Layout
  • CSS Box Model Module Level 3
  • LayoutNG

Related to the source code

  • /blink/renderer/core/layout

A Layout Tee is generated based on the DOM Tree to generate Layout information for each node. The process of Layout is to traverse the entire Layout Tree for Layout operations. The DOM Tree and Layout Tree are not always one-to-one. If we set dispaly: None in the tag, it will not create a Layout object.


04 Compositing Update

After the Layout operation is complete, it is theoretically possible to start Paint operation, but as we mentioned, it would be very expensive to start Paint operation and draw the entire interface. Therefore, the concept of layer composition acceleration is introduced. What is Compositing Layer?

The basic idea of layer composition acceleration is to divide the entire page into multiple layers according to certain rules (like layers in Photoshop), so that only the necessary layers need to be manipulated during rendering, and the other layers only need to be composited to improve rendering efficiency. The Thread that does this is called the Compositor Thread, which is worth noting that it also has the ability to handle input events (such as scrolling events), but if event listeners are registered in JavaScript, it forwards input events to the main Thread for processing.

Specifically, renderlayers have their own cache, called Compositing layers, from which the kernel creates the corresponding GraphicsLayer.

  • The RenderLayer that has its own GraphicsLayer draws in its own cache as it draws.
  • RenderLayer that doesn’t have its own GraphicsLayer will look up the parent’s GraphicsLayer until the RootRenderLayer (which always has its own GraphicsLayer), And then draw it in the cache of the parent node that has GraphicsLayer.

This creates a GraphicsLayer Tree that corresponds to the RenderLayer Tree. When the content of the Layer changes, you just need to update the GraphicsLayer, whereas with a single cache architecture, you update the entire Layer, which is time-consuming. This improves rendering efficiency. However, too many Graphicslayers can also consume memory, which reduces unnecessary drawing, but can also lead to poor overall rendering performance due to memory issues. Thus layer composition acceleration seeks a dynamic balance.

RenderLayer creates GraphicsLayer (GPU Accelerated Compositing in Chrome)

  • Layer has 3D or perspective transform CSS properties
  • Layer is used by element using accelerated video decoding
  • Layer is used by a element with a 3D context or accelerated 2D context
  • Layer is used for a composited plugin
  • Layer uses a CSS animation for its opacity or uses an animated webkit transform
  • Layer uses accelerated CSS filters
  • Layer has a descendant that is a compositing layer
  • Layer has a sibling with a lower z-index which has a compositing layer (in other words the layer overlaps a composited layer and should be rendered on top of it)

The layering decision is handled by Blink (which may move to the Layer Compositor decision in the future), which generates a Layer tree from the DOM tree and records the contents of each Layer in DisplayList. Now that we know about layer Compositing acceleration, let’s look at the Compositing update that happens after the Layout operation. The Compositing update is the process of creating a GraphicsLayer for the specific RenderLayer (the creation rules we’ve already described) as follows:


05 Prepaint

What is an attribute tree?

In the hierarchical structure of the description attribute this piece, before the way is to use layer tree way, if the parent layer with matrix transformation (translation, scaling, or perspective), cutting or special effects (filter, etc.), need recursive applied to child nodes, time complexity is O (layers), which could be a performance problem in extreme circumstances.

Therefore, the concept of attribute tree is introduced, and the synthesizer provides transformation tree, clipping tree, special effect tree, etc. Each layer is composed of several node ids corresponding to matrix transformation nodes, clipping nodes and special effects nodes of different attribute trees. Such time complexity is O(the node to change), as shown below:

The Prepaint process is the process of building a property tree, as follows:

06 Paint

Once the property tree (Prepaint) is created, the Paint phase begins. The related documents

Related to the source code

  • /blink/renderer/core/paint

The Paint operation converts Layout objects in a Layout Tree into drawing instructions (such as drawing rectangles, fonts, and colors, which are a bit like drawing API calls). These operations are then encapsulated in Dsipaly items, which are stored in PaintArtifact. PaintArtifact is the output of the Paint phase. So far, we’ve created a list of draw operations that can be replayed, but no actual draw operations have been performed.

Note: Recrod & Replay mechanism is used in most graphics systems now. The acquisition and execution of drawing instructions are separated from each other to improve rendering efficiency













  • The background color
  • floats
  • The foreground
  • outline

The Paint operation will eventually generate a Paint Tree based on the Layout Tree.





Layer Compositor

07 Commit

After the Paint phase is complete, enter the Commit phase. This phase updates a copy of the layer and property tree to the synthesizer thread to match the submitted main thread state. Copy layers and properties from the main thread to the synthesizer thread for use.


08 Tiling

However, after the synthesizer thread receives the data, it will not immediately start to synthesize, but to partition the layer, which involves a partition rendering technology. What is block rendering?

Tile Rendering is to divide the cache of a web page into small tiles, usually 256×256 or 512×512, and render them in blocks.

There are two main considerations for partitioned rendering:

  • GPU composition is usually implemented using OpenGL ES maps, where the cache is actually GL Texture. Many Gpus have limitations on the size of the Texture, such as length and width must be a power of 2, maximum 2048 or 4096, etc. Arbitrary size caches are not supported.
  • Block caching, so that browsers can use a unified buffer pool to manage the cache. The small cache of the buffer pool is shared by all WebViews. When a web page is opened, the small cache is applied to the buffer pool. When a web page is closed, the cache is reclaimed.

Tiling is the basic unit of rasterization. Rasterization prioritizes the blocks based on their distance from the visible viewport. Those that are close will be rasterized, and those that are far away will degrade rasterized priority. These blocks are stitched together to create a layer that looks like this:


09 Raster

Once the layers are partitioned, Raster is performed. What is rasterization (rasterization)?

Raterization, also known as rasterization, is used to execute drawing instructions to generate color values of pixels. There are two rasterization strategies:

  • Synchronous rasterization: Rasterization and composition in the same thread, or through thread synchronization to ensure light and composition
    • Direct Rasterization: Directly execute the drawing instructions for the visible areas in the eDisplayList of all visible layers to generate the color values of the pixels on the pixel buffer of the target Surface. Of course, if it is completely direct rasterization, there is no layer merge involved, and there is no need for subsequent composition.
    • Indirect rasterization: Allows additional buffers to be allocated for a layer that is rasterized to its own pixel buffer, The rendering engine then synthesizes and outputs the large ohmmeter Surface’s pixel buffers from these layers (view. setLayerType allows the application to assign pixel buffers to views). Android and Flutter mainly use direct rasterization of measurements, but also support indirect rasterization.
  • Asynchronous block rasterization




































































  1. In Proess Raster
  2. Out of Proess Raster

1. In the old version, Skia runs in Renderer Process and is responsible for generating GL instructions. GPU has a separate GPU Process, and Skia cannot directly make rendering system calls in this mode. When initializing Skia, give it back a table of function Pointers (pointing to the GL API, but not the real OpenGL API, but the Proxy provided by Chromium), The process of converting function pointer tables to the true OpenGL API is called command buffers (GpuChannelMsg_FlushCommandBuffers). A separate GPU process helps isolate GL operations, improving stability and security. This pattern is also known as the sandbox mechanism (unsafe operations run in separate processes).

























10 Activate

After Commit, there is an Activate operation before Draw. Raster and Draw both occur in the Layer Tree of the synthesizer thread, but we know that Raster operation is asynchronous, it may need to execute Draw operation, Raster operation is not completed, this time need to solve the problem. It divides the Layer tree into:

  • Pending Tree: Receives the COMMIT and Raster the Layer
  • Active Tree: Draws the rasterized Layer from here.

The copying process is called Activate and looks like this:








  • Main thread Layer tree: cc::Layer, always present.
  • Pending tree: CC ::LayerImpl, synthesizer thread, for rasterization phase, optional.
  • Active tree: cc::LayerImpl, the synthesizer thread, for the drawing phase, is always present.
  • Recycle trees: CC ::LayerImpl, synthesizer threads, and Pending trees do not coexist.

The main thread’s layer tree is owned by LayerTreeHost, and each layer has its sub-layers recursively. Pending trees, Active trees, and Recycle trees are all instances owned by LayerTreeHostImpl. These trees are defined under the CC /trees directory. They are called trees because earlier they were implemented based on tree structures, and today they are implemented as lists. After each block is rasterized, the synthesizer thread generates Draw Quads for each block, which are encapsulated in a CompositorFrame object. The CompositorFrame object is also the output of the Render Process. It will be submitted to the GPU Process. The Frame of 60fps output refers to a Compositor Frame. The Draw operation is the process of generating Draw Quads from rasterized blocks.


Display Compositor

12 Display

The related documents

After the Draw operation is complete, the Compositor frames are generated, which are output to the GPU Process. It receives Compositor frames from multiple Render processes from multiple sources.

  • The Browser Process also has its Compositor to generate Compositor frames, which are typically used to draw the Browser UI (navigation bars, Windows, etc.).
  • Each time a TAB is created or iframe is used, a separate Render Process is created.















Viz is short for VIsual, and it is an important part of Chromium’s overall architecture towards servitization, including Compositing, GL, Hit Testing, Media, VR/AR and many other functions.

VIz is also double-buffered, drawing Draw Quads in the background buffer and then executing swap commands to finally get them displayed on the screen. What is double buffering?

In the rendering process, if only a buffer is read and written, the screen will have to wait to read, while the GPU will have to wait to write, which will cause low performance. A natural idea is to separate reading and writing into:

  • Front Buffer: The screen reads frame data from the Front Buffer for output display.
  • Back Buffer: The GPU writes frame data to the Back Buffer.

The two buffer will not direct data copy (performance), but in the background buffer write complete, front desk buffer read complete, direct exchange of pointer, front desk becomes the background, the background at the front desk, so what time exchange, if the background buffer is ready to, the screen has not been processed at the front desk buffer, so there will be a problem, Obviously at this point you need to wait for screen processing to complete. After the screen is scanned, the device needs to go back to the first line to refresh. There is a Vertical Blank Interval during this period, which is the time for interaction. This operation is also known as VSync.

At this point, the rendering process is complete, and the front-end code becomes pixels that the user can interact with.