参考来源:http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome
WebKit的渲染引擎代码非常复杂,文档又比较欠缺。为了易于理解Chrome中GPU加速渲染的工作原理,最好先了解一下WebKit如何来渲染页面的。
我们先从非GPU加速的渲染来进行介绍,然后在此基础上再说GPU发挥了什么作用。
DOM树中,最根部的节点(Node)总是一个Document节点。
一个渲染对象知道如何绘制其对应的节点到画布上,它对图形环境(GraphicsContext)执行一系列绘图操作,然后由图形环境(GraphicsContext)将绘图产生的像素值映射到显示屏幕上。
在Chrome中,2D图形环境(GraphicsContext)封装在Skia库中,大部分的绘图调用,都是针对SkCanvas或者SkPlatformCanvas的(详细内容请参考Chrome Skia)。
在软件渲染模式下,整个页面只需要一个图形环境(GraphicsContext),所有的渲染对象(RenderObject)都对它进行绘制。
一般来讲,拥有相同坐标空间(如受控于相同的CSS变换)的渲染对象会属于同一个渲染图层。渲染图层可以保证渲染对象在重叠、半透明等情况时,能以正确层叠次序进行绘制。
RenderBoxModelObject::requiresLayer()中定义了一些为渲染对象创建新渲染图层的前提条件,如:
* 渲染对象是页面的根对象;
* 渲染对象有独立的CSS定位属性(相对、绝对、变换);
* 渲染对象是透明的;
* 覆盖有透明(Alpha)蒙版或者反射层;
* 有CSS效果滤镜;
* 该渲染对象对应于<canvas>标签指定的WebGL或者2D加速图形元素;
* 该渲染对象对应于<video>标签元素;
注意渲染对象与渲染图层间不存在一对一关系,一个渲染对象,要么对应于专为它创建的的渲染图层,要么对应于其某级根对象的渲染图层。
渲染图层(RenderLayers)也是以树形结构来组织的,根部的图层即对应渲染树(Render Tree)中根部的渲染对象。
每个渲染图层(RenderLayer)同时存储在两个基于不同深度值方向(Z-Order)的列表中:正向深度列表posZOrderList,以及负向深度列表negZOrderList。
* DOM树(DOM Tree),持有构成页面的所有的数据节点对象;
* 渲染对象树(RenderObject Tree),持有与可显示节点(Node)一对一的渲染对象,每个渲染对象知道如何绘制与其对应的节点;
软件渲染和硬件加速渲染,而软件渲染是最基本的方式。
软件渲染过程,整个页面中的每个渲染图层按照深度从后向前的顺序依次被绘制,渲染图层的主要绘制工作都是在RenderLayer::paintLayer()中完成,其中大概包含如下步骤:
a. 判断图层边界是否与刷新矩形有交叉;
b. 通过调用图层的paintLayer()方法,屏幕深度上从前向后,递归绘制negZOrderList列表中位于该图层后面的图层;
c. 让该图层相关联的所有渲染对象(RenderObject)完成各自的绘制;
d. 渲染对象(RenderObject)的绘制过程,从那个创建该图层的对象开始,向渲染对象树(RenderObject Tree)末端遍历,
直至遇到一个不属于当前渲染图层(RenderLayer)的渲染对象(RenderObject)而结束;
e. 通过调用图层的paintLayer()方法,屏幕深度上从后向前,递归绘制posZOrderList列表中位于该图层前面的图层。
在这种渲染方式下,渲染对象通过对绘图环境(GraphicsContext,Chrome中的Skia库)执行一系列绘图操作,将自己的内容绘制在内存位图上。
绘图环境本身并不关心图层的概念,但是在绘制半透明图层时有一点需要注意:半透明图层在开始绘制渲染对象时,会调用GraphicsContext::beginTransparencyLayer(),
在Skia库的实现中,这个调用会使得后续的所有绘制都在独立的位图上进行,以至于当该图层相对应的所有对象渲染完成时(此时endTransparencyLayer()方法被调用),
这些独立位图能够与基础图像(或者称背景图像)进行合成(进行必要的Alpha混合,以实现半透明效果)。
然后通过IPC消息通知浏览器进程进行界面更新,浏览器进程收到IPC通知后,使用操作系统API,将内存位图绘制到指定窗口(标签对应的网页视图)上。
WebKit的渲染引擎代码非常复杂,文档又比较欠缺。为了易于理解Chrome中GPU加速渲染的工作原理,最好先了解一下WebKit如何来渲染页面的。
我们先从非GPU加速的渲染来进行介绍,然后在此基础上再说GPU发挥了什么作用。
1. 节点(Nodes)和DOM树
在WebKit中,网页内容是通过由一些节点(Node)组成的树型结构组织在一起的,被称作DOM树。页面中的每个HTML元素以及元素携带的数据被保存在一个节点(Node)中。DOM树中,最根部的节点(Node)总是一个Document节点。
2. 节点(Nodes)与渲染对象(RenderObjects)
DOM树中每个可以显示的节点(Node),都对应一个渲染对象(RenderObject),渲染对象被存储在一个有层级的树形结构中,叫做渲染树(Render Tree)。一个渲染对象知道如何绘制其对应的节点到画布上,它对图形环境(GraphicsContext)执行一系列绘图操作,然后由图形环境(GraphicsContext)将绘图产生的像素值映射到显示屏幕上。
在Chrome中,2D图形环境(GraphicsContext)封装在Skia库中,大部分的绘图调用,都是针对SkCanvas或者SkPlatformCanvas的(详细内容请参考Chrome Skia)。
在软件渲染模式下,整个页面只需要一个图形环境(GraphicsContext),所有的渲染对象(RenderObject)都对它进行绘制。
3. 渲染对象(RenderObjects)与渲染图层(RenderLayers)
每个渲染对象(RenderObject)都有其对应的渲染图层(RenderLayer),或者是直接关联,或者是通过其根对象(其根级RenderObject)间接关联。一般来讲,拥有相同坐标空间(如受控于相同的CSS变换)的渲染对象会属于同一个渲染图层。渲染图层可以保证渲染对象在重叠、半透明等情况时,能以正确层叠次序进行绘制。
RenderBoxModelObject::requiresLayer()中定义了一些为渲染对象创建新渲染图层的前提条件,如:
* 渲染对象是页面的根对象;
* 渲染对象有独立的CSS定位属性(相对、绝对、变换);
* 渲染对象是透明的;
* 覆盖有透明(Alpha)蒙版或者反射层;
* 有CSS效果滤镜;
* 该渲染对象对应于<canvas>标签指定的WebGL或者2D加速图形元素;
* 该渲染对象对应于<video>标签元素;
注意渲染对象与渲染图层间不存在一对一关系,一个渲染对象,要么对应于专为它创建的的渲染图层,要么对应于其某级根对象的渲染图层。
渲染图层(RenderLayers)也是以树形结构来组织的,根部的图层即对应渲染树(Render Tree)中根部的渲染对象。
每个渲染图层(RenderLayer)同时存储在两个基于不同深度值方向(Z-Order)的列表中:正向深度列表posZOrderList,以及负向深度列表negZOrderList。
4. 三个树结构
可以说,渲染过程中,有三个树形结构各司其职:* DOM树(DOM Tree),持有构成页面的所有的数据节点对象;
* 渲染对象树(RenderObject Tree),持有与可显示节点(Node)一对一的渲染对象,每个渲染对象知道如何绘制与其对应的节点;
* 渲染图层树(RenderLayer Tree),基于渲染对象树构建的层级树,每个渲染图层对应一至多个渲染对象;
5. 软件渲染过程
WebKit在渲染页面时,从根节点开始遍历渲染图层树(RenderLayer Tree),直至叶子节点,在页面渲染的实现上,WebKit包含两种方式:软件渲染和硬件加速渲染,而软件渲染是最基本的方式。
软件渲染过程,整个页面中的每个渲染图层按照深度从后向前的顺序依次被绘制,渲染图层的主要绘制工作都是在RenderLayer::paintLayer()中完成,其中大概包含如下步骤:
a. 判断图层边界是否与刷新矩形有交叉;
b. 通过调用图层的paintLayer()方法,屏幕深度上从前向后,递归绘制negZOrderList列表中位于该图层后面的图层;
c. 让该图层相关联的所有渲染对象(RenderObject)完成各自的绘制;
d. 渲染对象(RenderObject)的绘制过程,从那个创建该图层的对象开始,向渲染对象树(RenderObject Tree)末端遍历,
直至遇到一个不属于当前渲染图层(RenderLayer)的渲染对象(RenderObject)而结束;
e. 通过调用图层的paintLayer()方法,屏幕深度上从后向前,递归绘制posZOrderList列表中位于该图层前面的图层。
在这种渲染方式下,渲染对象通过对绘图环境(GraphicsContext,Chrome中的Skia库)执行一系列绘图操作,将自己的内容绘制在内存位图上。
绘图环境本身并不关心图层的概念,但是在绘制半透明图层时有一点需要注意:半透明图层在开始绘制渲染对象时,会调用GraphicsContext::beginTransparencyLayer(),
在Skia库的实现中,这个调用会使得后续的所有绘制都在独立的位图上进行,以至于当该图层相对应的所有对象渲染完成时(此时endTransparencyLayer()方法被调用),
这些独立位图能够与基础图像(或者称背景图像)进行合成(进行必要的Alpha混合,以实现半透明效果)。
6. 将WebKit渲染结果显示在屏幕上
然后通过IPC消息通知浏览器进程进行界面更新,浏览器进程收到IPC通知后,使用操作系统API,将内存位图绘制到指定窗口(标签对应的网页视图)上。