对布局树进行分层,以及图层的绘制

551 阅读3分钟

一、分层

拥有了布局树以及各节点的布局信息,还不能进行页面的显示,因为页面中会存在一些设置了3D变换、z-index等属性,所以渲染引擎还需要为布局树中的一些特别的节点生成一个图层,并组成一个图层树。

页面就是多个图层的叠加。

节点会被生成单独的图层的条件:

  • 拥有层叠上下文的节点:叠加在根图层之上,z轴(面向用户)值越大的节点。

  • position: fixed

  • opacity小于1

  • 根元素

  • z-index值不为auto

  • transfrom不为none的等

  • 需要被裁剪的地址:当我们给一个div设置了宽度和高度,但是由于内容过多,超出了div,那么这个div就会被生成一个单独的图层。

  • 滚动条也会生成一个单独的图层。

最后会生成这样的一个图层树。

为什么要进行分层?

分层其实是浏览器的一个优化策略。如果没有分层,布局树直接生成目标图片的话,我们对页面的一些小的改动,都会造成整个页面的重排或者重绘,严重影响了页面的渲染效率。

二、绘制图层

有了图层树,渲染进程会对每一个图层进行拆分,拆分成多个绘制指令,然后按照这些绘制指令排成绘制列表。绘制列表可以在控制台--> Layers中查看,如下图:

可以在Details里面查看到图层的详细绘制信息。

一个元素要好几个绘制指令,因为每个元素的前景、背景、边框都需要单独的绘制指令。

三、拆分成图块

将图层拆分成绘制指令之后,就要开始绘制了,绘制是在渲染引擎的合成线程中进行的。

合成线程会将图层分成图块,图块的大小为256x256或者512x512。

拆分成图块的原因是不能一次性直接绘制出所有的图层内容,因为开销太大,所以只能将图层拆分成多个图块,优先绘制靠近视口位置的图块。

四、栅格化

栅格化就是将图块转成位图。

渲染进程维护了一个栅格化线程池,所有的图块栅格化都在这个线程池中进行的,使用了GPU加速,生成具体的位图也是在GPU中进行的。

渲染进程发送绘制的指令给GPU进程,GPU进程会对图块进行栅格化,生成位图,并将位图保存在GPU的内存中。

每一个图层都对应一张位图。

五、合成和显示

当所有的图块都被栅格化了之后,合成线程会将这些位图合成一张图,然后给浏览器主进程发送命令,表示已经绘制完成图块,浏览器主进程的viz组件在接收到之后,将合成后的图存到后缓冲区。

合成新的图像的工作都在显卡中进行。

一旦显卡把新的生成的图片放到后缓冲区,系统就会让前后缓冲区互换,显示器只读取前缓冲区的内容。

通常情况下,显卡的更新频率和显示器的读取频率是一致的,通常是60HZ,也就是每秒读取60张图片。