晋城网站建设,一键建站平台,大专网站建设论文,wordpress android 下载《WebKit 技术内幕》之八#xff08;1#xff09;#xff1a;硬件加速机制
1 硬件加速基础
1.1 概念 这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页#xff0c;因为GPU的作用主要是用来绘制3D图形并且性能特别好#xff0c;这是它的专长所在#xff0c;它…《WebKit 技术内幕》之八1硬件加速机制
1 硬件加速基础
1.1 概念 这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页因为GPU的作用主要是用来绘制3D图形并且性能特别好这是它的专长所在它同软件渲染有很多不同的地方既有自己的优点当然也有些不足之处。 对于GPU绘图而言通常不像软件渲染那样只是计算其中更新的区域一旦有更新请求如果没有分层引擎可能需要重新绘制所有的区域因为计算更新部分对GPU来说可能耗费更多的时间。当网页分层之后部分区域的更新可能只在网页的一层或者几层而不需要将整个网页都重新绘制。通过重新绘制网页的一个或者几个层并将它们和其他之前绘制完的层合成起来既能使用GPU的能力又能够减少重绘的开销。 之前笔者总是将RenderLayer对象和最终显示出来的图形层次一一对应起来也就是每个RenderLayer对象都有一个后端存储与其对应这样有很多好处那就是当每一层更新的时候WebKit只需要更新RenderLayer对象包含的节点即可。所以当某一层有任何更新时候WebKit重绘该层的所有内容当然对于Tiledlayer不是这样的情况。这是理想情况在现实中不一定会这样主要原因是实际中的硬件能力和资源有限。为了节省GPU的内存资源硬件加速机制在RenderLayer树建立之后需要做三件事情来完成网页的渲染。
WebKit决定将哪些RenderLayer对象组合在一起形成一个有后端存储的新层这一新层不久后会用于之后的合成Compositing这里称之为合成层Compositing Layer。每个新层都有一个或者多个后端存储这里的后端存储可能是GPU的内存。对于一个RenderLayer对象如果它没有后端存储的新层那么就使用它的父亲所使用的合成层。将每个合成层包含的这些RenderLayer内容绘制在合成层的后端存储中如第7章所述这里的绘制可以是软件绘制也可以是硬件绘制。由合成器Compositor将多个合成层合成起来形成网页的最终可视化结果实际就是一张图片。合成器是一种能够将多个合成层按照这些层的前后顺序、合成层的3D变形等设置而合成一个图像结果的设施后面会介绍Chromium合成器的工作原理。 在WebKit中只有把编译的C代码宏macro“ACCELERATED_COMPOSITING”打开之后硬件加速机制才会被开启有关硬件加速的基础设施才会被编译进去。
1.2 WebKit硬件加速设施 一个RenderLayer对象如果需要后端存储它会创建一个RenderLayerBacking对象该对象负责Renderlayer对象所需要的各种存储。正如前面所述理想情况下每个RenderLayer都可以创建自己的后端存储但事实上不是所有RenderLayer都有自己的RenderLayerBacking对象。如果一个RenderLayer对象被WebKit依照一定的规则创建了后端存储那么该RenderLayer被称为合成层。 每个合成层都有一个RenderLayerBacking RenderLayerBacking负责管理RenderLayer所需要的所有后端存储因为后端存储可能需要多个存储空间。在WebKit中存储空间使用GraphicsLayer类来表示下图描述了这些主要类和它们的关系。 图WebKit的硬件加速基础类 上图的上半部分是WebKit项目中WebCore部分的四个基础类RenderLayer和RenderLayerBacking已经做过一些介绍了GraphicsLayer表示RenderLayer中前景层、背景层所需要的一个后端存储。每个GraphicsLayer都使用一个GraphicsLayerClient对象该对象能够收到GraphicsLayer的一些状态更新信息并且包含一个绘制该GraphicsLayer对象的方法RenderLayerBacking继承于该类。GraphicsLayer是WebKit中的基础类主要定义一套标准接口在WebKit不同的移植中它们有不同的子类及其实现图8-1的下半部分是两个不同移植的具体实现类。 哪些RenderLayer对象可以是合成层呢如果一个RenderLayer对象具有以下的特征之一那么它就是合成层。
RenderLayer具有CSS 3D属性或者CSS透视效果。RenderLayer包含的RenderObject节点表示的是使用硬件加速的视频解码技术的HTML5“video”元素。RenderLayer包含的RenderObject节点表示的是使用硬件加速的Canvas 2D元素或者WebGL技术。RenderLayer使用了CSS透明效果的动画或者CSS变换的动画。RenderLayer使用了硬件加速的CSS Filters技术。RenderLayer使用了剪裁Clip或者反射Reflection属性并且它的后代中包括一个合成层。RenderLayer有一个Z坐标比自己小的兄弟节点且该节点是一个合成层。 至于为什么这么做有以下三个原因首先当然是合并一些RenderLayer层这样可以减少内存的使用量其二是在合并之后尽量减少合并带来的重绘性能和处理上的困难其三对于那些使用单独层能够显著提升性能的RenderLayer对象可以继续使用这些好处例如使用WebGL技术的canvas元素。 下图描述了RenderLayer树、RenderLayerBacking对象和GraphicsLayer树这些硬件加速基础设施的对应关系。RenderLayer树中的第四个节点没有创建RenderLayerBacking对象因为不符合上面的创建条件而对于每个RenderLayerBacking对象它也至少需要一个GraphicsLayer对象当然也可能需要多个图中的RenderLayerBacking对象分别需要2个、1个和4个GraphicsLayer对象这些对象分别表示什么呢图8-3描述了一个RenderLayerBacking对象可能包括的众多GraphicsLayer对象层它们表示不同的含义。 图RenderLayer树、RenderLayerBacking对象和GraphicsLayer树 图RenderLayerBacking包含的各种GraphicsLayer对象层 为什么一个RenderLayerBacking对象需要这么多层呢原因有很多例如WebKit需要将滚动条独立开来称为一个层需要两个容器层来表示RenderLayer对应的Z坐标为正数的子女和Z坐标为负数的子女需要滚动的内容建立新层还可能需要剪裁层和反射层。那么这些层是如何被组织并且它们被绘制的顺序是如何呢上图中的树状结构描述了所有层的绘制顺序按照先根顺序遍历的结果即是绘制顺序图中每个层就是一个GraphicsLayer对象。对于某个RenderLayerBacking对象来说其主层是肯定存在的其他层则不一定存在因为不是每个RenderLayer对象都需要用到它们。 图RenderLayerBacking中包含的GraphicsLayer对象
管理这些合成层等工作的是RenderLayerCompositor类这个类可以说是个“大管家”。它不仅计算和决定哪些RenderLayer对象是合成层而且为合成层创建GraphicsLayer对象如图8-5所示。每个RenderView对象包含一个RenderLayerCompositor这些对象仅在硬件加速机制下才会被创建。RenderLayerCompositor类本身也类似于一个RenderLayerBacking类也就是说它也包含一些GraphicsLayer对象这些对象对应的是整个网页所需要的后端存储。 图RenderLayerCompositor类
1.3 硬件渲染过程
介绍完硬件加速机制所使用的内部设施之后同前面介绍的软件渲染机制一样下面详细分析硬件渲染机制过程。渲染的一般过程在本章最开始的时候已经描述过这里主要介绍WebKit是如何具体实现这一过程的。
示例代码8-1给出了一个网页该网页中使用了很多HTML5新功能它必须使用硬件加速机制才能够渲染因为这其中的CSS 3D变形、WebGL和Video等都是HTML5引入的新特性这些新特性必须依赖GPU硬件加速才能达到比较好的效果。
示例代码8-1需要硬件加速机制的HTML5网页 htmlstylediv{-webkit-transform:rotateY(10deg);}/stylebodyptest text/pdivcss 3d transform/divcanvas idwebglwidth80height80/canvasvideo width400height300controlscontrolssource srctest.oggtypevideo/ogg/videoscript typetext/javascriptvar canvasdocument.getElementById(webgl);var glcanvas.getContext(experimental-webgl);gl.clearColor(0.0, 1.0, 0.0, 1.0);gl.clear(gl.COLOR_BUFFER_BIT);/script/body/html首先看WebKit是如何确定并计算合成层的图8-6描述了WebKit如何决定哪些层是合成层并为它们分配后端存储的过程。图中主要包含两个部分都是RenderLayerCompositor类的函数一是检查RenderLayer对象是否为合成层如果是的话为它们创建后端存储对象RenderLayerBacking二是根据重新更新的合成层来更改合成层树并修改后端存储对象的一个设置信息。 图WebKit决定合成层并构建合成层树 除了上图之外当RenderLayer对象被创建时网页还有一些其他情况也可能需要创建RenderLayerBacking对象。具体的过程是由RenderLayerModelObject::styleDidChanged()函数调用RenderLayer::styleChanged()函数来触发然后WebKit调用RenderLayerCompositor::updateLayerCompositingState()函数为RenderLayerModelObject对象所在的RenderLayer层来创建后端存储对象。 下图主要描述的是WebKit为示例代码8-1建立的合成层和合成层相应的RenderLayerBacking对象。根据前面的解释WebKit为网页中的5个DOM节点创建RenderLayer对象分别为HTMLDocument对象、HTMLHtmlElement对象、HTMLDivElement对象、HTMLCanvas对象和HTMLVideo对象。但是图中只有4个RenderLayerBacking对象这是因为HTMLHtmlElment对象对应的RenderLayer没有自己的RenderLayerBacking对象原因是该RenderLayer对象不满足之前所描述的规则。 图示例代码的RenderLayer树和RenderLayerBacking对象 其次WebKit需要遍历和绘制每一个合成层也就是每个合成层可能有一个或者多个RenderLayer对象这可能包含至少四种情形第一种情形是HTMLDocument节点WebKit绘制该节点所在的合成层需要遍历两个RenderLayer对象所包含的子树与其他绘制的内容的调用过程非常相似该合成层也需要一个用于2D图形的图形上下文对象该对象的内部实现由各个移植来决定具体的2D绘图在后面介绍。该层的调用过程如图8-8所示该过程同软件渲染非常类似只是递归过程稍微不同。 图绘制HTMLDocument对应的RenderLayer层 在软件渲染过程中paintLayer函数被递归调用也就是从RenderLayer根节点开始直到所有的RenderLayer对象都被遍历为止。在硬件加速机制中情况有所不同这是因为引入了合成层的概念每个RenderLayer对象被绘制到祖先链中最近的合成层。示例代码是WebKit中RenderLayer::paintLayer()函数的条件判断部分的代码用来检查是否在父节点所在的后端存储中绘制当前节点。如果它不是合成层那么就继续绘制该层如果它是的话那么就直接返回。在之后的逻辑中WebKit会重新为每一个合成层调用绘制操作每个合成层的图形上下文都不一样这点不像软件渲染过程。 示例代码WebKit的RenderLayer::paintLayer()函数的条件判断 RenderLayer::paintLayer(){if (isComposited()){if (context-updatingControlTints()||(paintingInfo.paintBehaviorPaintBehaviorFlattenCompositingLayers)){paintFlags|PaintLayerTemporaryClipRects;}else if (!backing()-paintsIntoWindow()!backing()-paintsIntoCompositedAncestor()!shouldDoSoftwarePaint(this, paintFlagsPaintLayerPaintingReflection)){//If this RenderLayer should paint into its backing, thatwill be done via RenderLayerBacking::paintIntoLayer().return;}}else if (viewportConstrainedNotCompositedReason()NotCompositedForBoundsOutOfView){return;}}第二种情形是使用CSS 3D变形的合成层这在本章8.3.3节中介绍。第三种情形是使用WebGL技术的Canvas元素所在的合成层它的绘制是由JavaScript操作来完成的并且使用了3D的图形上下文后面会在8.3.1节中介绍。第四种情形是类似使用了硬件加速的视频元素所在的合成层该层的内容其实是由视频解码器来绘制而后通过定时器或者其他通知机制来告诉WebKit该层内容已经发生变化需要重新合成这在后面的章节中介绍。 最后一个步骤是渲染引擎将所有绘制完的合成层合成起来这个是由WebKit的移植来完成的在本章的8.2.3小节中将做详细的介绍。
1.4 3D图形上下文 WebKit中的3D图形上下文主要是提供一组抽象接口这组接口能够提供类似OpenGLES使用GPU硬件能力的3D图形应用编程接口的功能其主要目的当然也是使用OpenGL绘制3D图形的能力。这一层抽象能够将WebKit各个移植的不同部分隐藏起来WebCore只是使用统一的抽象接口。在WebKit中3D图形上下文的主要用途是WebGL当然启用硬件加速的Canvas2D等HTML5技术也会使用3D图形技术不过情况有些不同。 下图给出了WebKit的GraphicsContext3D类该类是一个抽象类其包含的接口所处理的对象就是OpenGL中所提供的能力例如针对纹理、着色器、纹理贴图、顶点等GL操作不过这里是一个C类的封装而已。 图WebKit的3D图形上下文相关类 上图中的GraphicsContext3DPrivate就是一个跟WebKit的各个移植相关的类虽然在各个移植中都是使用该名称但是每个移植的定义非常不同它主要是针对移植的不同来实现的。PlatformGraphicsContext3D类是WebCore用于创建Surface等对象的参数所以其名字是一致的但是每个移植的定义实际上不一样。 GraphicsContext3D中的接口有三种类型第一类是所有移植共享实现的接口例如texImage2DResourceSafe第二类是一些移植能够共享实现的接口例如texImage2D它们可以直接调用OpenGL或者OpenGL ES的应用编程接口第三类则是跟每个移植具体相关例如platformGraphicsContext3D。 这些跟移植相关的类都是需要每个移植去实现的否则这一机制不能工作下面的部分就是Chromium移植如何实现这些部分并包含哪些不同之处。