开启硬件加速时Web页面绘制流程


对于每一个RenderLayer,我们可以为其单独创建一块内部存储(有些情况下可以为多个layer创建同一块存储),这些存储会被用来保存该层中的内容,浏览器最后会把这些所有的层通过GPU合成起来,形成最终网页渲染的内容,这就是硬件加速合成。


一、WebKit支持


在建立DOM树后,如前面所述,WebKit会创建相应的Render树和RenderLayer树。如果启用加速合成(accelerated_compositing)选项,WebKit会做一些特别的处理。

它为每个RenderLayer创建一个RenderLayerBacking,这个类非常的有用,它是用来管理和控制RenderLayer的合成相关的事情,决定对该层是否做优化,同时包含了很多GraphicsLayer的对象。GraphicsLayer类是一种抽象,用于表示有后端存储(backingstore)的渲染surface,同时,也包括作用于之上的各种变换(transformation)和动画(animation)。RenderLayerBacking类中包含的这些GraphicsLayer有内容层,可能还有前景层(Foreground),剪切层(clipping)等。下图中的WebKit部分是WebKit中为渲染和硬件加速所涉及的类,在此一一介绍。

RenderLayerCompositor::WebKit中渲染部分掌控大局的类,管理RenderLayer树结构,它通过浏览器的设置来决定是否创建RenderLayer以及是否硬件加速合成,同时也决定是否为RenderLayer创建RenderLayerBacking

RenderLayerBacking:用来管理和控制相对应的RenderLayer的合成行为,包含很多GraphicsLayer对象,这些对象用于表示层内容,前景(foreground)内容等等

GraphicsLayer:用于表示有后端存储(backingstore)的渲染surface及其相应的变换等,该类是一个抽象类,不同平台的移植有不同的实现

androidGraphicsLayer的具体移植为GraphicsLayerAndroid类,其相关函数在经过WebKitlayout,paint之后会被调用到:

#0 WebCore::GraphicsLayerAndroid::setPosition GraphicsLayerAndroid.cpp:277

#1 WebCore::RenderLayerBacking::updateGraphicsLayerGeometryRenderLayerBacking.cpp:390

#2 WebCore::RenderLayerCompositor::updateCompositingDescendantGeometryRenderLayerCompositor.cpp:1168

#3 WebCore::RenderLayerCompositor::updateCompositingDescendantGeometryRenderLayerCompositor.cpp:1198

#4 WebCore::RenderLayerCompositor::updateCompositingDescendantGeometryRenderLayerCompositor.cpp:1198

#5 WebCore::RenderLayerBacking::updateAfterLayoutRenderLayerBacking.cpp:250

#6 WebCore::RenderLayer::updateLayerPositionsRenderLayer.cpp:387

#7 WebCore::FrameView::layoutFrameView.cpp:1000


GraphicsLayerAndroid类中含有LayerAndroid类的对象,其所有函数都会转发的LayerAndroid类中做相应动作


二、渲染模型


渲染大体可以分为2个过程,paintdrawpaint过程是按照webkit渲染之后生成的绘制动作来绘制canvas。而draw过程则是将canvas显示到屏幕上。其中draw过程较为简单,还是以paint过程为主。

1.layer

paint过程中,WebView使用一种类似webkitlayer树结构.该树的根节点是BaseLayerAndroid,余下的其他节点则用LayerAndroid表示。其中BaseLayerAndroid代表最大的“surface”,通常就是一个普通web页面的内容。该类中含有一个PictureSet,包含了绘制该web页面的所有步骤。该PictureSet可以理解为是由webkit生成并传递过来的。而LayerAndroid类中只包含一个SkPicture,SkPicture记录了绘制一个canvas的一系列绘制命令。LayerAndroid代表较小的“surface”,其通常对应于特殊的块,如 fixedposition divs,or elements using CSS3D transforms, or containing video, plugins,等等。

所以我们现在关注的paint过程,只是BaseLayerAndroidpaint过程。


2.瓦片策略

一个BaseLayerAndroid由一组tile构成,就类似于被很多瓷砖覆盖的地面。BaseLayerAndroid可能很大,一般策略是这一组tile仅覆盖viewport的区域,并且将webview的内容(绘制步骤存储在BaseLayerAndroidPictureSet中)绘制在tile上,最后将tile显示在屏幕上.因此每次都要检查需要使用哪些tile


TiledPage代表了上述的,覆盖viewport的一组tile(由BaseTile类表示).当渲染的时候,需调用TiledPage::prepare()来准备,然后它自己绘制到屏幕上。


这里需要插一句,每一个GLWebViewState会含有2TiledPagefrontand background,一个在当前比例显示页面,另一个在后台绘制不同比例下的页面. 例如,当我们缩放一个TiledPage,它的tiles会有某种程度的失真.为了解决这个问题,当用户停止缩放,我们会在新的比例下绘制backgroundTilePage. backgroundTilePage准备就绪,我们把它和当前正在显示的TilePage交换。


TilePageprepare()函数决定了哪些tile需要绘制以及以什么样的顺序绘制。当覆盖viewporttiles准备好时,就可以开始绘制。prepare的过程比较重要,如果prepare不能成功,则整个渲染过程也不能成功。prepare过程中会调用到TiledPage::prepareRow,在此函数中才是真正的准备过程。此函数会判断本行中哪些tile落在当前viewport内,并且该BaseTile被标记为dirty,则未该BaseTile获取渲染纹理。然后调用TexturesGenerator线程来为该BaseTile进行绘制。



3.纹理分配


很显然不能让每个BaseTile都有一个GL纹理–我们需要从一个纹理池中获取GL纹理,然后重复使用它们。获取纹理(BaseTile::reserveTexture())是一个比较重要的过程,在TiledPage::prepare()函数中,需要组织起所需的tile(viewport范围内且标记为dirty)到一个TilesSet,并调用BaseTile::reserveTexture()为每一个tile分配一个专门的后台纹理。它会调用TilesManager::getAvailableTexture来获取纹理。


TilesManager类是一个管理类型的类,它负责管理各种纹理。该类中有一个可用纹理池,纹理池中的纹理数量由之前计算得来,通常是viewport中所能包含的最多tile数的两倍。

为何是两倍?因为每个BaseTile中有2个纹理,m_frontTexturem_backTexture。与TiledPage道理一个,一个是当前显示的纹理,另一个在后台进行绘制,然后再交换两者。


reserveTexture()TilesManager类来请求纹理。分配机制如下:

-优先分配与前一次相同的纹理

-优先分配远离viewport的纹理

-优先分配不同TiledPage的纹理




BaseTile失效


如果tile是最新的,则不会被重绘.Tile只有被认为是dirty的时候才需要重绘

-tile获取新的纹理

-webkit使tile的全部或部分内容失效


为了处理webkit使tile的全部或部分内容失效的情况,每个tile中存储了2ids(counters) of the pictureSets. The first id (A) represents thepictureSet used to paint the tile and the second id (B) representsthe pictureSet in which the tile was invalidated by webkit.Thus, if A < B then tile is dirty.


Sinceinvalidates can occur faster than a full tiled page update, the tiledpage is protected by a 'lock' (m_baseLayerUpdate) that is set to trueto defer updates to the background layer, giving the foreground timeto render content instead of constantly flushing with invalidates.See lockBaseLayerUpdate() & unlockBaseLayerUpdate().


绘制顺序


Thenext operation is to schedule this TilesSet to be painted(TilesManager::schedulePaintForTilesSet()). TexturesGenerator willget the TilesSet and ask the BaseTiles in it to be painted.


BaseTile::paintBitmap()将使用BaseLayer'sPictureSet来绘制纹理(callingTiledPage::paintBaseLayerContent() which in turns callsGLWebViewState::paintBaseLayerContent()).


TexturesGenerator运行在一个专门的线程,纹理通过EGLImages来共享(thisis necessary to not slow down the rendering speed -- updating GLtextures in the main GL thread would slow things down).


Tile生命周期

1. 每一个tile在主GL线程中被创建,并被分配到TiledPage的特定位置.


2. When needed the tile is passed to the background thread where itpaints the BaseLayer's most recent PictureSet to a bitmap which is thenuploaded to the GPU.


3. bitmap被上传到GPU之后,主GL线程将调用tiledraw()函数,来将tile显示在屏幕上


4. Steps 2-3 are repeated as necessary.

5.当用户切换到新页面时tile被销毁


prepare过程完成之后,paint过程就结束了。


三、渲染流程


WebKit::WebView::onDraw函数开始,WebView控件尝试在屏幕上绘制出其内容,该函数会调用drawContent,调用到nativeGetDrawGLFunction来获取drawGL的函数对象。然后再将函数对象传递给GLES20Canvas->callDrawGLFunction,该函数将调用到PDK中的内容。从PDK一路调用到android::WebView::drawGL,然后调用WebCore::GLWebViewState::drawGL,就开始进入WebCore中的处理。这部分代码位于WebCore/platform/graphics/android目录下,是与平台相关的部分。WebKit提供了基础设施,但要实现硬件加速合成,各个移植还有很多事要做


BaseLayerAndroid::drawGL()函数(实际上是所有的drawGL函数,比如WebView::drawGL TreeManager::drawGL)返回true,表示绘制还没有完成,drawGL系列函数会被继续调用,直到绘制完成。


上述步骤2中的后台线程指的是TexturesGenerator线程,在TexturesGenerator中定义,在TilesManager类的构造函数中被初始化,并被启动。其会在TexturesGenerator::threadLoop函数中进行业务处理,没有事情时会wait,并等待唤醒。而唤醒该线程通常是外界通过调用TexturesGenerator::scheduleOperation函数来进行。该线程最终会调用到BaseLayerAndroid::drawCanvas函数来将PictureSet画到SkCanvas上。


步骤3draw()函数的调用流程为:

#0 WebCore::BaseTile::draw BaseTile.cpp:249

#1 WebCore::TiledPage::drawGL TiledPage.cpp:381

#2 WebCore::BaseLayerAndroid::drawBasePictureInGLBaseLayerAndroid.cpp:315

#3 WebCore::BaseLayerAndroid::drawGL BaseLayerAndroid.cpp:363

#4 WebCore::TreeManager::drawGL TreeManager.cpp:266

#5 WebCore::GLWebViewState::drawGL GLWebViewState.cpp:508

#6 android::WebView::drawGL WebView.cpp:432

你可能感兴趣的:(开启硬件加速时Web页面绘制流程)