像素的一生

HTML+CSS | 2021-05-08 10:46:50 1943次 3次

主题

Chrome 如何将 Web Content 转化成像素。


Pixels

微信图片_20210508105958.jpg

chrome 依赖底层操作系统提供的图形库,将像素显示到屏幕上,现在大部分平台上有一个叫 OpenGL 的 API 标准,Windows 系统中有时还需要额外转换成 DirectX,未来还会支持更加新的 API 比如 Vulkan,这些库提供了底层的图形学基本类型,比如纹理和着色器,比如把这些坐标上的多边形绘制到虚拟像素的缓冲区中。


Stages

未标题-1.png

Parsing

未标题-1.png

渲染的起点就是 html 等解析,dom 树解析,样式计算,合并渲染树等。(这部分就是常见的浏览器渲染原理的过程)


Paint

未标题-2.png

拿到了布局对象的几何位置信息,可以开始绘制,Paint 过程会把所有绘制操作记录到待显示项目的列表中,绘制操作如上图右上角指定坐标内画一个红色矩形这样的动作。每个布局对象对应有多个与其视觉外观相对的待显示项。目前只是记录绘制操作,还没有真正执行,后续还能重放这些操作。

未标题-1.png

绘制过程中先绘制绿色框再绘制蓝色框,背景绘制阶段先绘制了所有背景,然后前景绘制阶段再绘制文本。


Raster

未标题-2.png

列表中各个待显示的绘制操作是由栅格化进程执行,并且是异步的(异步和同步光栅化)。它的过程是讲列表中的全部或部分待显示项转换为颜色值的位图,位图中的每个单元格记录四通道色值,栅格位图保存在内存中。通常是由 OpenDL 纹理对象引用的 GPU 内存,GPU 不仅可以保存输出的位图,还可以执行生成位图的命令,这一过程我们叫快速光栅化或 GPU 光栅化。

目前位置这些像素还在内存中,没有显示在屏幕上,要生成位图。

未标题-3.png

栅格化通过 SKIA 库生成 OpenGL 调用,SKIA 提供了一层对硬件的抽象,能理解更复杂的东西,比如路径和贝塞尔曲线,所以在栅格化待显示项时,绘制操作会调用这个 SKIA 中的 SKCanvas 对象,然后还会经过更多层的处理。实际上 SKIA 用 GPU 加速代码路径并为绘线操作建立独立的缓冲区,在栅格任务结束时会释放输出缓冲区内容,得到实际构建纹理的 OpenGL 命令。


Gpu

SKIA 是无法直接调用 OpenGL 的,渲染进程是在沙箱中进行,不能直接进行系统调用。SKIA 调用 OpenGl 是通过用命令缓冲区机制,代理传输到 GPU 进程,它接受命令缓冲区,并通过 GL API 对象的一组函数指针生成真正的 GL 调用。

需要 GPU 进程有两个原因:

1. 需要绕过渲染沙箱机制

2. OpenGL 使用的是图形驱动程序,不稳定或有安全漏洞,采用 GPU 隔离 GL,提供一些保护措施。假如 GPU 进程挂了浏览器可以在后台启动。

在大多数平台上,这些 GL API 函数指针,是通过系统共享的 OpenGL 库的动态查找并初始化的,在 windows 中则来自 ANGLE 的库。它的工作就是把 OPenGL 翻译成 DirectX(微软提供,用于在windows上加速图形渲染)。

在将来,栅格化都将从渲染进程转移到 GPU 进程中,这意味着绘制操作的传输代理将由 GPU 命令缓冲区变为 IPC 通道,应该能带来性能的提升。


Invalidation

未标题-4.png

每秒 60 帧是一个黄金准则,这是由典型硬件上的垂直同步间隔决定的,如果超过 1/60s 的时间来渲染一帧,就会产生动画卡顿。最容易想到的一种优化就是跟踪发生改变的部分,复用无变更的部分。

每个管道流程阶段都有精细化失效的概念,比如说这个节点需要在下一帧重新计算布局,然后下一帧将只重新布局被标记为需要变更的节点。但是当一些滚动操作,造成的光栅化消耗也会非常大。

因为 dom 存在于主线程,但是因为 js线程 长时间占用执行耗时长的任务也会造成卡顿。


Compositing

未标题-1.png

合成有两种思想:

一是将页面分解为多个图层

另一种是把这些图层在另一个单独的线程上进行合成。

一个图层就是网页的一部分,它能够独立于其他图层进行变换和栅格化。

合成线程需要负责处理滚动输入事件所需的一切,而主线程忙于处理 js 之类的其他事情。


Slimming Paint

未标题-2.png

更细粒度的合成决策,让合成操作尽可能不依赖于绘制的顺序和其他东西。这里把待显示项中的具有公共属性的 chunk 提取出来创建图层,过去与图层关联的那些属性现在存在各自的属性树结构中。


Commit

未标题-1.png

它通过更新合成线程上的图层树的副本来匹配主线程上图层树的状态。当主线程阻塞时,提交过程就运行在合成线程上,它能安全地读取主线程的图层树。

注意 paint 阶段之后才是光栅化线程进行操作。为了把绘制操作的对象转化为位图。

合成线程将图层划分为图块,图块是栅格化操作的单位,栅格化有自己专门的线程来处理(查看详情)。合成线程有一个叫图块管理器的对象,它根据它们与视图的距离来创建图块,并在该工作池上按照优先级安排栅格化任务,每个栅格任务都会为特定图块生成位图。


Drawing

未标题-2.png

当所有图块混合到一起时,合成线程将生成“Quad 绘线”,一个 quad 像是在屏幕上的特定位置绘制图块的指令,同时考虑图层树所应用的所有变换。

每个 Quad 都引用内存中栅格图块的输出,提交到浏览器进程。

浏览器进程里面有一个叫 viz 的组件(ipc通信),用来接收合成线程发过来的DrawQuad命令,然后根据DrawQuad命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。


未标题-3.png

3人赞

分享到: