这篇文章提供chrome基于硬件加速的组合实现的背景和细节
说明:为什么用硬件合成
传统式,web浏览器完全依赖CPU来渲染网页内容,但是随着现在GPUs的能力以及能够以更小的体积嵌入设备,人们逐渐把关注点转向寻找
更有效地使用基础硬件来实现更好的性能和节省电源消耗,使用GPU来合成网页内容能够带来非常明显的提速
使用硬件合成的优点可以归结为三个因素:
1、在绘制和组合操作包含大量像素的页面方面,GPU上的合成页面层能够实现比CPU(在速度和绘制能力上)更好,更高效。硬件特别为这些类型
的工作而设计
2、对于已经放在在GPU上面的页面内容(浏览器生成的内容位图),昂贵的回读通常是不必要的,例如accelerated video,canvas2d,webgl
3、CPU和GPU的并行工作机制能够使操作在同一时间创建更高效的绘图管道
注:Cpu绘制(软件绘制)通常把所有渲染对象画到一张位图里面,然后从RAM发送到GPU中,常见的绘制方式由软件绘制(cpu)和GPU组合3种类型
各有自己的使用场景
接下来,在我们正式开始之前有一个重大的声明:chrome的绘制堆栈在过去几年中一直持续演化改进,这篇文章将会关注最新的浏览器架构,
但并不是讨论对各个平台的配置和功能分解,查看http://dev.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome/gpu-architecture-roadmap
代码路径在这里只会少量涉及
第一部分:Blink的渲染基础
Blink渲染引擎的源代码非常庞大,复杂,同时很少有文档记录。为了能够理解GPU加速器如何在Chrome中工作,首先理解Blink如何渲染
页面的基础构造块知识非常重要
1、节点和Dom树
对于Blink来说,页面内容通常内部存储为一棵包含节点对象的树,成为dom tree。页面上的各个html元素和文本都关联为一个节点,dom tree
的最顶层节点通常是document node
2、从节点到渲染对象
有dom tree的各个node节点生成的可视化输出对应为renderObject,renderObject 存储在和dom tree平行的树结构中,成为render tree,
一个渲染对象知道如何绘制一个Node内容到显示设备上,解决这样的必要绘制通过调用GraphicsContext实现,GraphicsContext把像素写进
位图并最终显示到屏幕上面。对于Chrome来说 GraphicsContext使用了Skia ,我们的2D绘制库
传统上大多数GraphicsContext调用通过调用SkCanvas或者SkPlatformCanvas.比如立即绘制成软件位图,除了绘制离开主线程,这些命令现在
被记录为一个skpicture,它是一个序列化数据结构能够捕获并且随后可以重放的命令,类似于 http://en.wikipedia.org/wiki/Display_list
二者不是一一对应关系,如Document节点,不可见节点,匿名块,补充一点就是匿名块的场景,
RenderInline 只能包含inline元素,当renderInline包含block元素是会创建匿名块把block元素包住,且匿名块是inline,RenderBlock的子节点要么全部是inline,要么全部是block,
当子节点同时包含inline和block元素时,会默认匿名RenderBlock来包含这些inline元素,并把他们作为匿名块的子元素
3、从渲染对象到渲染层(from renderObjects to RenderLayers)
各个渲染对象都直接或间接通过ancestore renderobject关联到应该渲染层RenderLayer
共享相同的坐标空间的RenderObjects属于相同的RenderLayer,正是因为RenderLayer的存在页面的各个元素才能按照正确的顺序合成并正确显示
层叠的内容,半透明元素等等,在一些条件下会触发为一个特殊的渲染对象RenderObject创建一个新的渲染层,这个定义在RenderBoxModelObject::
requiresLayer()并被一些子类重写,下面的RenderObject保证会创建RenderLayer
1、页面的root object
2、拥有显式的CSS位置属性定义(relative,absolute或者transform)
3、透明的元素
4、指定overflow,alpha mask或者reflection
5、指定css filter
6、对应canvas元素有3Dcontext或者加速的2D contxt
7、对应video元素
注意RenderObjects和RenderLayers并不一定一一对应,一个特定的RenderObject 是可能和一个为它创建的RenderLayer关联,或者如果第一个父级
节点关联的RenderLayout
RenderLayer也是树形结构,根节点的RenderLayer对应页面根节点元素同时可视化后代子元素对应的层包含在父元素的层里面。个子层保留在两个
排序列表中,包括升序顺序,negZOrderList包含子层指定了negative z-indices和posZOrderList包含子层只能指定positive z-indices
4、从渲染层到绘制层 From RenderLayers to GraphicsLayers
为了使用合成器,部分RenderLayers获取他们字段backing surface(靠背) (layers with their own backing surfaces are broadly referred to as compositing layers)
各RenderLayer都拥有自己的GraphicsLayer(if it is a compositing layer)或者使用第一级拥有GraphicsLayer的父节点,这个关系和RenderObject与RenderLayer之间的关系类似
每个GraphicsLayer都拥有GraphicsContext以供关联RenderLayers绘制,在后续合成步骤中,合成器负责最总合并GraphicsContexts输出的位图成最总屏幕显示图片
然而理论上每个单一的RenderLayer都能够自己绘制成单独的backing surface,就内存而言,这非常可能造成浪费。当前的Blink实现,下列的条件一定是满足一个RenderObject
来拥有它自己的组合层compositing layer
1、指定3D或者transform css样式属性的层
2、被video用来加速video解码的才的层
3、包含3Dcontext或者加速2D context(accelerated 2d context)的canvas元素使用的层
4、用于合成插件的层 layer is used for composited plugin
原文
Layer has 3D or perspective transform CSS properties
Layer is used by <video> element using accelerated video decoding
Layer is used by a <canvas> element with a 3D context or accelerated 2D context
Layer is used for a composited plugin
Layer uses a CSS animation for its opacity or uses an animated webkit transform
Layer uses accelerated CSS filters
Layer has a descendant that is a compositing layer
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)
5、层挤压
无不例外,就像上述而言,GraphicsLayer 可能非常耗费内存和其他资源(例如GraphicsLayer tree的一些关键操作可能占用很多比例的CPU时间),创建一些耗费的额外层,这些层和它的backing surface可能相互重叠,可能非常耗费资源
We call intrinsic compositing reasons (e.g. a layer that has a 3D transform on it) “direct” compositing reasons. To prevent a “layer explosion” when many elements are on top of a layer with a direct compositing reason, Blink takes multiple RenderLayers overlapping a direct-compositing-reason RenderLayer and “squashes” them into a single backing store. This prevents the layer explosion caused by overlap. More detail motivating layer squashing can be found in this presentation, and more detail on the code in between RenderLayers and compositing layers can be found in this presentation; both are current as of approximately Jan 2014 although this code is undergoing significant change in 2014.
6、从绘制层到weblayers到chrome compositor (From GraphicsLayers to WebLayers to CC Layers)
Only a couple more layers of abstraction to go before we get to Chrome’s compositor implementation! GraphicsLayers can represent their content via one or more Web*Layers. These are interfaces that WebKit ports needed to implement; see Blink’s public/platform directory for interfaces such as WebContentsLayer.h or WebScrollbarLayer.h. Chrome’s implementations are in src/webkit/renderer/compositor_bindings which implement the abstract Web*Layer interfaces using Chrome compositor layer types.
Putting it Together: The Compositing Forest
In summary, there are conceptually four parallel tree structures in place that serve slightly different purposes for rendering:
Each GraphicsLayer has Web*Layers implemented in Chrome with Chrome compositor layers. It is these final “cc layers” (cc = Chrome compositor) that the compositor knows how to operate on.
From here on in this document “layer” is going to refer to a generic cc layer, since for hardware compositing these are the most interesting -- but don’t be fooled, elsewhere when someone says “layer” they might be referring to any of the above constructs!
The Compositing Forest
Now that we’ve (briefly) covered the data structures in Blink that link the DOM to the compositor, we’re ready to explore the compositor itself in earnest.
http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome
http://www.webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/