【译】chrome – GPU加速的图层组合操作

原文:http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome

译注:(专业词汇对应翻译)

Node(节点)
DOM Tree(DOM树)
RenderObject(渲染对象)
RenderTree(渲染树)
GraphicsContext(图形环境对象、图形上下文对象)
一个Graphics Context默示一个绘制目标。它包含绘制体系用于完成绘制指令的绘制参数和设备相干信息。Graphics Context定义了根蒂根基的绘制属性,如色彩、裁减区域、线条宽度和样式信息、字体信息、混淆模式等。来自 <http://www.byywee.com/page/M0/S772/772925.html>
Bitmap位图
RenderLayers渲染图层
Alpha mask透明遮罩
Css filtercss滤镜
Software Rendering path软件渲染模式。译成“软件渲染路径”、“软件渲染路线”都可以,它是webkit渲染页面时的传统模式,不依赖硬件加速。
HWND返回窗体或控件的句柄(注意 OLE容器控件不支持该属性。句柄:是由操作环境定义的一个唯一的整数值,它被程序用来标识或者切换到对象,如窗体或控件等。)来自 <http://baike.baidu.com/link?url=knrqRLDl2voMqg6N6pq97dWrZGaxwR7G7gwW4HQyHzn6WGTflGg0nnms9afq7oARZ1hDaduE-81jnuxXQaGziq>
IPCIPC(Inter-Process Communication,进程间通信) 来自 <http://baike.baidu.com/view/373.htm>

概要

本文档阐述chrome浏览器“硬件加速图层组合”的背景和实现细节。

介绍

一般情况下,web浏览器完全依赖CPU进行网页内容的渲染。随着GPU在硬件设备(即便是很小的硬设)中的集成应用,以及富媒体例如视频、3D效果等在网页体验中扮演着越来越重要的角色,人们开始注意想方设法高效利用底层硬件获取更好的性能、电源节能。诚然,利用GPU直接对网页内容进行图层组合可以带来显著的性能提升(译注:这里的性能应该是指渲染速度方面)。最明显的例子莫过于video元素,它利用硬件进行视频解码,利用WebGL为H5 canvas提供硬件3D加速图形绘制渲染,期间占用的内存区域是CPU无法快速存取的。(译注:WebGL参考百科文档)

将网页图层组合的操作扔给GPU还有别的诸多好处,在大多数情况下,GPU在涉及大量像素的图形绘制、组合操作方面比CPU快的多,因为GPU是专门设计善干这类事情的硬件。此外,充分利用GPU做图形绘制、组合这类工作的同时,CPU就有更多的可以并行地做其他方面的运算,这种并行工作的方式创建了一个高效的图形管道。

Part 1  Webkit渲染基础及软件渲染模式

Webkit渲染引擎的源码巨大且复杂,晦涩难懂,几乎没啥米注释!为了弄清楚GPU在chrome里面如何工作,我们得先了解下webkit渲染网页的基本构件流程。下面我们从webkit如何工作作为基本出发点,回头再慢慢引入GPU影响渲染的过程,最终了解GPU如何工作。

节点和DOM树

在Webkit里面,网页内容内部存储为一个节点对象的树,我们称之为DOM树。网页上的每个标签包括标签之间的文本,各自对应DOM树上的一个节点。DOM树最上面的节点即Document节点。

从节点到渲染对象

DOM树里面的每个视觉可见的节点,均有一个相对应的渲染对象。在webkit内,渲染对象被存储成树形数据结构,和DOM树并行,我们称之为渲染树。渲染对象知道如何在显示介质(译注:例如显示器)上呈现(绘制)对应DOM树节点的内容,具体的方式是调用图形环境对象的绘制指令。而图形环境对象负责将像素写入到位图中去,最终被显示器显示出来。在chrome里面,图形环境对象封装了一个名为Skia的2D绘图库,于是大部分绘制指令被委托给SkCanvas或者SkPlatformCanvas执行。(关于chrome如何使用Skia库,可以参考这篇文档

在软件渲染模式里,整个页面只有一个图形环境对象,所有的渲染对象被绘制到这个共享的图形环境对象中。

从渲染对象到渲染图层

每个渲染对象通过其父级渲染对象直接或间接地关联一个渲染图层。

共享相同坐标空间的渲染对象(如被相同css变形影响的哪些对象)一般情况下属于同一个渲染图层。渲染图层的存在,使得页面的元素可以按正确的顺序进行组合,使得重叠的元素、半透明的元素等等得以恰当的渲染显示。触发webkit为渲染对象创建新的渲染图层的条件有很多,具体可见源码,在方法RenderBoxModelObject::requiresLayer()或者该方法在其他类的重载方法里可以窥其一二。总的来说,对于渲染对象,只要满足下面情形之一,均会致使新的渲染图层的创建。

  1. 它是页面的根对象。(译注:应该就是document节点对应的渲染对象)
  2. 它有显式的css 位置属性。(relative,absolute,或transform)
  3. 它是透明的
  4. 它有overflow,透明遮罩或阴影(反光)
  5. 它有css滤镜
  6. 它对应的节点是3D环境或2D加速环境的canvas元素
  7. 它对应的节点是video元素

值得注意的是,渲染对象和渲染图层并不是1对1的关系。一个渲染对象所关联的渲染图层,要么是为它自身创建的渲染图层,要么是它父级对象所关联的渲染图层(如果有多个有渲染图层的父对象,取最近的那个)。(译注:同一个树路径上的多个渲染对象可能会关联同一个渲染图层)。

渲染对象是树形结构,显然渲染图层也会是树形的。渲染图层树的根节点对应页面的根元素,每个图层节点的下行图层节点(子孙节点)对应该图层视觉包含的图层(译注:视觉包含不一定是dom树上的父子、祖孙节点)。每个图层节点的子图层节点(译注:是子节点不是子孙节点)被分类存储于两个升序排序的队列(negZOrderList和posZOrderList)中,队列negZOrderList包含z轴次序比当前图层低的图层(因而这类图层在渲染图层树的位置在当前图层下面),posZOrderList反之亦然。

凑到一起:我们有很多的树

总结下前面的内容,从概念上来看我们一共有3棵并行的树结构,各自在渲染过程中的作用不尽相同:

  1. DOM树(Dom Tree),是我们最基本的模型
  2.  渲染对象树 (RenderObject Tree),其节点和DOM树的可见节点是一对一的关系。渲染过程中,渲染对象知道如果绘制其对应的Dom节点。
  3.  渲染图层树(RenderLayer Tree),由渲染图层构成。其节点和渲染对象树的节点是1对多的关系,因为一个渲染对象关联的渲染图层要么是它自身的,要么是它父级对象的。渲染图层树体现了图层之间的z轴顺序。

软件渲染模式

从根本上来说,webkit渲染页面的时候,是从根图层节点开始,进而逐级递归遍历渲染图层树。对于渲染页面的过程,Webkit的代码库里有两种迥异的编码实现过程,一个是软件渲染过程,另一个是硬件加速的渲染过程,前者是传统的渲染模式。

在软件渲染模式中,网页渲染的时候被按照渲染图层树从上而下进行,(译注:图层树体现了图层之间的z轴顺序,所以从上而下实则为从里到外,z轴越小越先被渲染。另外这里的z轴顺序和css里面的z-index有关系但并没有对应关系的,css里面的z-index是元素的,这里指的是渲染图层的。)图层被渲染的复杂过程可以参考下源码里面的RenderLayer::paintLayer()方法,为简明起见下面从这个方法里面简化提取了几个基本的步骤:

  1. 如果图层有效性校验失败,直接退出该方法。【译注:原文是图层与已坏矩形区域(the damage rect,没上下文不知道怎么翻译这玩意)发生交错,则及早退出该方法】
  2. 递归调用该图层的negZOrderList队列中的子图层的paintLayer()方法
  3. 请求该图层关联的渲染对象去绘制自身。【译注:别忘了前面提到的,渲染对象知道如何在显示介质上绘制其对应的dom节点的内容】
  4. 这个请求渲染对象绘制自身的过程,是从创建了该渲染图层的那个渲染对象开始,依据渲染对象树,对其子节点进行递归遍历绘制处理。一旦发现某个渲染对象所关联的渲染图层不是当前被渲染的图层,则停止递归遍历绘制处理。
  5. 递归调用该图层的posZOrderList队列中的子图层的paintLayer()方法

在这个模式中,渲染对象调用一个共享的图形环境对象的绘制方法,将自身绘制到目标位图中,最终被显示器显示出来。【译注:可回头看看前面的“从节点到渲染对象”小节】

要注意的是,图形环境对象本身并没有图层的概念,为了正确绘制半透明效果的图层,需要做些特别的处理:半透明效果的渲染图层在请求其关联的渲染对象绘制自身之前,会先调用图形环境对象的beginTransparencyLayer()方法。在Skia图形库实现的图形环境对象中,调用beginTransparencyLayer()方法,到导致接下来相关的渲染对象绘制自身至新的位图中,当这些渲染对象绘制完毕后,会调用一个对应的endTransparencyLayer()方法。最后,beginTransparencyLayer方法内创建的位图对象,会和paintLayer()方法创建的位图对象组合在一起,最终被显示器显示出来。

【译注:半透明效果的渲染图层,其渲染绘制的过程大概是这样的:paintLayer() => beginTransparencyLayer() => 调用关联的渲染对象的绘制方法 => endTransparenceLayer(),paintLayer和beginTransparencyLayer都会导致在内存中创建位图对象,最后两个位图对象组合在一起最终显示出来。】

从Webkit到显示器

当所有的渲染图层被绘制到一个共享位图之后,该位图需要在显示器上被显示出来。在chrome里面,位图存储于共享内存中,经由IPC(进程间通讯)传输至浏览器进程。浏览器进程负责调用操作系统的视窗API(例如windows操作系统中的HWND),将位图绘制到网页对应的标签页或窗口中去。

发表评论

电子邮件地址不会被公开。 必填项已用*标注