Chromium 渲染流水线——字节码到像素的一生

Chromium 渲染流水线——字节码到像素的一生

💡 原文中文,约25900字,阅读约需62分钟。
📝

内容提要

本文介绍 Chromium 渲染流水线从网络字节到屏幕像素的 13 个阶段:解析生成 DOM 树,样式计算生成 Render Tree,布局确定几何信息,预绘制生成属性树,绘制生成绘制指令,提交至合成线程,分层、分块、光栅化,激活后生成 DrawQuad,最终由 Viz 进程合成上屏;同时介绍浏览器内核与进程模型,并对比同步与异步光栅化策略的优劣。

🔎

延伸解读

进程分工决定渲染边界

文章指出 Chromium 渲染涉及 Browser、Render、Viz 三类进程:Render Process 负责单个 Tab 内单站点的解析、样式、布局、绘制与光栅化,Viz Process 负责接收各进程的 CompositorFrame 并合成上屏。理解这一分工,有助于判断卡顿发生在主线程、合成线程还是 Viz 合成阶段,而不是笼统归因于“浏览器慢”。

分层与分块是性能换内存

Compositing 将页面拆成独立图层,Tiling 再把图层拆成 256x256 或 512x512 的图块,使滚动和动画只需重绘必要区域。文章也提醒,每个 Layer 都消耗内存,异步光栅化“很吃内存”,浏览器内核性能很大程度靠内存换取。因此 will-change 等优化并非越多越好,需权衡图层数量与内存占用。

同步与异步光栅化各有取舍

文章对比两种策略:同步光栅化内存占用极好、首屏略早、动态内容重渲染效率高,但低端机上易持续掉帧;异步光栅化在图层动画和惯性滚动上优势明显,却内存占用差,快速滚动时可能出现白屏或 DOM 更新不同步。选择优化方向时,应结合设备性能与页面内容是否频繁变化来判断。

CSS 阻塞渲染有明确原因

文章强调 DOM 构建后不会立刻渲染,需等待 CSS 处理完毕,因为只渲染无样式的 DOM 没有意义。CSS 解析还涉及从右向左的选择器匹配和 RuleMap 分类存储,最终按 Cascade layers、选择器优先级、proximity 和声明顺序计算样式。这解释了为何样式表加载与选择器结构会影响首屏和样式重算成本。

❓

Q&A

Chromium 的渲染流水线一共包含哪些阶段?

Chromium 渲染流水线从网络字节到屏幕像素共包含 13 个阶段:Parsing、Style、Layout、Pre-paint、Paint、Commit、Compositing、Tiling、Raster、Activate、Draw、Aggregate、Display。

Chromium 的进程模型是怎样的?主要涉及哪些进程?

Chromium 有 5 类进程:Browser Process(1 个)、Utility Process(1 个)、Viz Process(1 个)、Plugin Process(多个)、Render Process(多个)。与渲染强相关的是 Browser Process、Render Process 和 Viz Process。Render Process 负责单个 Tab 内站点的渲染、动画、滚动和 Input 事件;Browser Process 负责浏览器 UI 的渲染、动画、路由和 Input 事件;Viz Process 接收并合成 CompositorFrame,最终使用 GPU 上屏。

为什么 Chromium 需要 Compositing 阶段?它解决了什么问题?

Compositing 阶段将页面分成多个独立图层,便于隔离更新。如果没有分层,一个简单的滚动会导致所有像素重新 Paint 和 Raster,容易因数据未就绪而丢帧(Janky)。分层后,Chromium 只需操作必要的图层,其他图层参与合成即可,从而提高渲染效率。例如,有 transform 动画的元素会成为独立图层,动画只渲染该图层。

同步光栅化和异步光栅化有什么区别?各自优缺点是什么?

同步光栅化中 Compositor 和 Raster 同步进行,流水线简单;异步光栅化则分块进行,光栅化和合成不在同一线程且不同步。同步光栅化内存占用极好、首屏性能好、动态内容渲染效率高,但光栅化性能较低,低端机略弱;异步光栅化内存占用极差、首屏性能一般、动态内容渲染效率低,但对图层动画和惯性动画有绝对优势,光栅化性能好。

Chromium 渲染流水线中 Parsing 阶段的具体流程是什么?

Parsing 阶段由 Blink 在 Render Process 的 Main thread 执行,将网络字节解析为 DOM Tree。数据流为:bytes → characters → token → nodes → object model (DOM Tree)。具体包括 5 个环节:Loading(从网络线程接收 bytes)、Conversion(将 bytes 转为 characters)、Tokenizing(将 characters 转为 W3C 标准 token)、Lexing(通过词法分析将 token 转为 Element 对象)、DOM construction(使用 Element 对象构建 DOM Tree)。

什么是分块渲染(Tiling)?为什么需要分块渲染?

分块渲染是将网页缓存分为多个小块(通常为 256x256 或 512x512)进行渲染。需要分块渲染的原因有两个:一是 GPU 合成通常使用 OpenGL ES 贴图,很多 GPU 对纹理大小有限制,无法支持任意大小的缓存;二是分块缓存方便浏览器使用统一的缓冲池来管理缓存,所有 WebView 共用小块缓存,打开网页时申请,关闭时回收。

🏷️

标签

➡️

继续阅读