1.RenderObject(绘制可见内容的实体)
- RenderObject上实现了将对应DOM节点绘制进位图的方法,负责绘制DOM节点可见内容
因为有层的覆盖
2.RenderObject 生成 RenderLayer 的条件(定义层的单位)
-
每个RenderLayer的子Layer放在两个升序列表
- negZOrderList储存z-index为负的renderLayer
- posZOrderList储存z-index为正的renderLayer
根元素
明确的 CSS 定位属性(relative,absolute,transform)
是透明的(transparent)
有 overflow,alpha mask 遮罩,reflection
CSS filter
有 3D 上下文或者加速 2D 上下文的画布(canvas)
video 元素
因为动画需要快速绘制,单独提取
3.RenderLayer 生成 Graphics Layer(合成层)
- 3D或透视变换(perspective,transform)
- 使用加速视频解码的元素
- 拥有3D上下文或者加速2D上下文
- 混合插件(flash)
- 对opacity,transform,fliter,backdropfilter应用了动画或者渐变
- will-change设置为opacity,transform,top,left,bottom,right
- 拥有加速CSS过滤器的元素
- 拥有低z-index且包含一个复合层的兄弟元素
- 将不需要特殊处理能合成的直接合成一个 renderLayer
- 将不能被直接合成的多个静态 renderLayer 特殊处理后合成为一个 Graphics Layer
- 将静态的 Graphics Layer 和动态的 Graphics Layer 进行动静合成成最终的合成
- Graphics Layer负责将自己的Render Layer及其子代所包含的Render Object绘制到位图里。然后将位图作为纹理交给GPU。所以现在GPU收到了HTML元素的Graphics Layer的纹理,也可能还收到某些因为有3d transform之类属性而提升为Graphics Layer的元素的纹理.
- 现在GPU需要对多层纹理进行合成(composite),同时GPU在纹理合成时对于每一层纹理都可以指定不同的合成参数,从而实现对纹理进行transform、mask、opacity等等操作之后再合成,而且GPU对于这个过程是底层硬件加速的,性能很好。最终,纹理合成为一幅内容最终draw到屏幕上.
4. 具体实现
- 相关进程
- 渲染进程:每个tab一个,负责执行js和页面渲染
- 主线程(Main Thread)
- 合成器线程(Compositor Thread)
- 瓦片工人线程(Tile Worker)
- GPU进程:整个浏览器一个,负责将Render进程绘制好的瓦片位图作为纹理上传到GPU,并调用GPU相关方draw到屏幕上
- GPU线程(GPU Thread)
- 相关线程工作
主线程
JS执行,重新计算样式,更新层树,写进位图,合成层合成器线程
接受浏览器发出的垂直同步信号,也接受OS传来的用户交互(滚动,输入,点击)
- 如果可能,合成器线程会自己处理这些内容,转换为对layer的位移和处理,并将新的帧commit到GPU线程,直接输出页面
- 如果你在滚轮事件注册了回调,这时合成器线程就会唤醒主线程,让后者执行JS,完成DOM的计算重排,产出新的纹理,再commit到GPU Thread
- 瓦片线程
由Compositor 线程创建,专门将瓦片光栅化
整体流程
接收到Vsync信号,新的一帧开始
合成器线程将之前接收到的用户UI交互传给主线程处理
限定每帧一次requestAnimationFrame
parse HTML dom变动解析dom
Recalc Styles 重新计算样式
Layout重排,
update layer tree
处理层变动Paint
记录哪些绘画调用,放进一个列表主线程计算各种混合参数并把数据交给合成器线程,接着处理input回调
Raster Scheduled and Rasterize
光栅化commit
所有瓦片被光栅化后,合成器线程就会commit到GPU线程,GPU线程把位图作为纹理上到到GPU里,并调用平台对应3DAPI把所有纹理绘制到一个位图里,从而完成纹理的合并
5.具体细节
重排,强制重排
大小位置改变会触发重排,如果在标记为dirty的情况下访问了offsetTop等属性就会强制重排重绘
以合成层为单位