什么是GPU
提到GPU加速器,我们会想起很多术语,比如 GPU Accelerated Compositing,再比如 hardware-accelerated Compositing,这些都是一个意思。为什么要做GPU加速呢,因为它在图像渲染方面的表现优于CPU,而且GPU可以和CPU共同工作,极大的提升渲染性能。 那么GPU(Graphic Processing Unit)是什么呢? GPU即图形处理器,又称显示核心、视觉处理器、显示芯片,是一种专门在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上进行图像运算工作的微处理器。GPU最大的优势在于它高性能,低成本,可以短时间内完成大量的图像处理任务,远超CPU,而且不会影响CPU的性能。 那么GPU的工作内容都包含哪些呢?
- 顶点处理:根据顶点数据描绘3D图形骨架,这一步主要由Vertax Shader(定点着色器)完成
- 光栅化计算:显示器显示的图像是由像素组成的,将矢量图形(点和线)转化成像素的操作称为光栅化,比如一条斜线,被转化为阶梯状的连续像素,统一通过调用Skia图形库提供的绘图接口完成
- 纹理贴图:对应第一步的操作,第一步结束后,会对每一块多边形进行贴图(纹理映射 texture mapping),有TMU(Texture Mapping Unit)完成
- 像素处理:这个阶段发生于第二步之后,确认每个像素的最终属性,由Pixel Shader(像素着色器)完成
- 最终输出:由ROP(光栅化引擎)完成,一帧渲染完毕后,被送到显存帧缓冲区
浏览器渲染原理
RenderObject到 RenderLayer
在之前的文章中提到过,浏览器的加载渲染过程,但只提到了生成渲染树,在DOM中,每一个可视的Node都会对应一个RenderObject或者LayoutObject,组成RenderTree。每一个RenderObject都会对应一个RenderLayer或者PaintLayer,或者对应其祖先RenderObject的RenderLayer。 一般来说,有相同坐标空间的RenderObject,拥有相同的RenderLayer,RenderLayer最初是为了实现层叠上下文(stacking context),保证绘制的顺序和透明度,因此满足层叠上下文条件,就会生成一个新的RenderLayer。 总结生成RenderLayer的条件:
NormalPaintLayer
- 根节点
- 有明确的css位置属性,比如
relativeabsolutetransform - 透明的
- 有css filter属性
- 有css mask属性
- 有css reflection属性
- 有 CSS mix-blend-mode 属性(不为 normal)
- 有 CSS transform 属性(不为 none)
- backface-visibility 属性为 hidden
- 有 CSS column-count 属性(不为 auto)或者 有 CSS column-width 属性(不为 auto)
- 当前有对于 opacity、transform、fliter、backdrop-filter 应用动画
OverflowClipPaintLayer
- overflow不为visible
NoPaintLayer
- 不需要 paint 的 PaintLayer,比如一个没有视觉属性(背景、颜色、阴影等)的空 div。
满足上述条件的RenderObject有独立的RenderLayer,其余的和其第一个拥有RenderLayer的祖先RenderObject共享。
RenderLayers 也形成一个树层次结构。根节点是对应于页面中根元素的 RenderLayer,每个节点的后代都是视觉上包含在父层中的层。每个 RenderLayer 的子级都保存在两个按升序排序的列表中,negZOrderList 包含具有负 z 索引的子层(因此层低于当前层),posZOrderList 包含具有正 z 索引的子层(当前层之上的层)。
RenderLayer 到 GraphicsLayer
某些RenderLayer被认为是合成层(compositin layers, layers with their own backing surfaces),被认为是合成层的渲染层拥有独立的GraphicsLayer,其余的则和其第一个拥有 GraphicsLayer 父层共用一个,这类似于 RenderObject 与 RenderLayers 的关系。之所以不是每个渲染层都是合成层,主要还是为了性能。
那么渲染层在哪些情况会被认为是合成层呢?首先得是SelfPaintLayer(约等于NormalPaintLayer)
直接原因
- css backface-visibility: hidden
2. 对 opacity、transform、fliter、backdropfilter 应用了 animation 或者 transition(需要是 active 的 animation 或者 transition,当 animation 或者 transition 效果未开始或结束后,提升合成层也会失效)
3. video
4. 覆盖在video上的视频控制栏
5. 3D 或者 硬件加速的 2D Canvas 元素
6. 在 DPI 较高的屏幕上,fix 定位的元素会自动地被提升到合成层中
7. will-change 设置为 opacity、transform、top、left、bottom、right(其中 top、left 等需要设置明确的定位属性,如 relative 等
后代元素原因
- 有合成层后代同时本身有 transform、opactiy(小于 1)、mask、fliter、reflection 属性
3. 有合成层后代同时本身fixed定位
4. 有合成层后代同时本身overflow不为visible
5. 有 3D transfrom 的合成层后代同时本身有 preserves-3d、perspective 属性
overlap重叠
如果自身本来不具备成为合成层的条件,但却与合成层重叠,此时为了保证层叠顺序正确,某些情况下,该渲染层会被提升为合成层。举个简单的例子,但具体情况要复杂的多,这里不做详细的描述。用官方原话来说:
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) 即兄弟元素中存在叠放顺序较低的合成层
<body>
<div style="position: absolute; top: -100px; left: 100px; animation: fadeIn 100s;width: 400px; height:300px; background-color: pink;"></div>
<div style="position: absolute; width: 400px; height:300px; background-color: aquamarine; z-index: 999;"></div>
</body>
层压缩
Layer Squashing,为什么会有这一步,由于上面提到的各种各样的原因,生成合成层的原因有很多,尤其是层重叠,随随便便就能产生很多合成层,这非常耗费性能,有一种情况下是可以压缩合成层的,就是比如有多个兄弟渲染层因为层叠顺序较高被提升为合成层时,这几个兄弟层可以压缩为一个层。