CC(浏览器渲染机制之合成器线程做了啥)
其实浏览器绘制的整体流程就是Blink一顿操作,并在paint阶段生成cc的数据源,cc进行一系列操作并最终在draw阶段将结果(CF)提交给viz。也就是说,Blink负责网页内容绘制,cc负责将绘制的结果合成并提交给viz。 (现在说有一点早哈。。。我滴错)
commit
我们在前面的操作得到了什么,得到了Layer list和property tree。
于是,commit阶段的核心作用就是更新Layer list(其实一般都叫它layer tree,但是其实他是list)和property trees的副本到合成器线程(compositor线程,也被称为Impl1线程)。 在commit完成之后会根据需要创建Tiles任务,Tiles任务会被Post到Raster线程。
所以,这个阶段做的事情很好理解,就是把前面主进程的产物拷贝一份到合成器线程。
现在的流程图:
Tiling
Tiling阶段介绍
合成器线程接收到数据之后,不会立即开始合成,而是把图层进行分块。这里涉及到一个”分块渲染“的技术,分块渲染会将网页的缓存分成一块一块的,比如:256*256的块,之后进行分块渲染。
为什么要分块渲染?
- GPU合成通常是使用OpenGL ES贴图实现的,这时候的缓存实际就是纹理(GL Texture),很多GPU对纹理的大小是有限制的,比如长宽必须是2的幂次方,最大不能超过2048或者4096等。无法支持任意大小的缓存。
- 分块缓存,方便浏览器使用统一的缓冲池来管理缓存。缓冲池的小块缓存由所有WebView共用,打开网页的时候向缓冲池申请小块缓存,关闭网页是这些缓存被回收。 tiling图块也是栅格化的基本单位,栅格化会根据图块与可见视口的距离安排优先顺序进行栅格化。离得近的会被优先栅格化,离得远的会降级栅格化的优先级。
分块最后的结果是 cc:TileTask
Tiling阶段总结
这一阶段会对图层进行分块,最终产生 cc:TileTask, cc:TileTask也是下一个阶段的输入。
输入:cc:layer list
输出:cc:TileTask
目前的流程图:
Raster(光栅化)
Raster阶段介绍
光栅化会执行每一个TileTask, 将图块转换成颜色值的位图。生成的位图中每个单元都保存着这个位图的颜色值与透明度的编码(比如 FFFFFFF,其实就是RGBA的16进制表示)。
不仅如此,光栅化这个过程还会去解码嵌入在页面中的图像资源,绘制操作会引用压缩的数据(比如JPEG,PNG等等),而光栅化会调用适当的解码器对其进行适当的解压。
所以,简单来说,光栅化,就是把图块转换成带有颜色透明度信息的位图的过程。
Raster阶段总结
在这个阶段,会把图块转换成位图,存储在内存中,当然这个内存地址的引用也会被记录,记录在 cc::PictureLayerImpl中(以后会用!)。
输入:cc:TileTask
输出:位图
目前的流程图:
Activate
在Commit之后,Draw之前有一个Activate操作。Raster和Draw都发生在合成器线程里的Layer List上,但是我们知道Raster操作是异步的,有可能需要执行Draw操作的时候,Raster操作还没完成,这个时候就需要解决这个问题。
于是它将LayerTree分为了:
- PendingTree:负责接收commit,然后将Layer进行Raster操作
- ActiveTree:会从这里取出光栅化好的Layer进行draw操作。
如图所示,这样保证了,接下来的操作拿的layer一定是已经光栅化好的。
目的:由于raster是异步的,于是为了使draw拿的数据是raster完成的数据,所以引入了activate这个操作!!!!
目前流程图:
Draw
Draw阶段介绍
一看这个名字,就知道整个阶段已经接近了尾声,没错,Draw也确实是合成器线程执行操作的最后一个阶段。
到了Draw这个步骤,当每个图块都被光栅化之后,合成器线程会为每个图块生成draw quads(在屏幕的指定位置绘制图块的指令,也包含了属性树里面的变换,特效等操作),这些draw quads会被封装在CompositorFrame对象里面,CompositorFrame对象也是Render Process(渲染进程)的产物,它会被提交到Gpu Process中。
Draw指的就是 把光栅化的图块,转换成draw quads的过程。 最后CompositorFrame会发送到viz进程(GPU进程)进行最后的渲染。
前文说到过,”在Raster阶段,会把图块转换成位图,存储在内存中,当然这个内存地址的引用也会被记录,记录在 cc::PictureLayerImpl中(以后会用!)。“,不知道记不记得这句话,现在用到了,我们要知道draw quads里面有什么。其实我们主要关心的就是,里面有 绘制的操作(paintOp)和对应位图地址的引用。draw quads会被放在CompositorFrame(CF)中,提交给GPU进程,去完成最后一个阶段。
到此,合成器线程的主要工作也做完了。撒花,合成器线程,你辛苦了。
Draw阶段总结
draw阶段将图块转换成draw quads,里面包含绘制指令,属性树的变换,和位图的地址。draw quad是会被放在CompositorFrame这个对象里面,提交给GPU进程。
输入:光栅化完成的图块
输出:饱含大家希望的CompositorFrame
目前的流程图:
GPU
VIZ
在 Chromium 中 viz 的核心逻辑运行在 GPU 进程中,负责接收其他进程产生的 viz::CompositorFrame(简称 CF),然后把这些 CF 进行合成,并将合成的结果最终渲染在窗口上。
于是在此,我们的代码就成功的渲染在了网页上了,冰冷的代码变成了温暖的五彩斑斓的页面~~
总结
完整流程图