转载请注明原文地址:http://blog.csdn.net/milado_nju

## 概述

在前面的章节中,笔者介绍了WebKit渲染引擎是如何有HTML网页构建DOM树、RenderObject树到RenderLayer树,以及它们之间的对应关系。这一渲染基础被软件渲染和硬件渲染共享,也就是说不管哪种类型的渲染机制,WebKit渲染引擎都会构建它们。不过对于软件渲染而言,到RenderLayer树就结束了,后面不会建立其它额外的树来对应于RenderLayer树。但是,对于硬件渲染来说,这是漫长阶段的一个部分,在RenderLayer树之后,WebKit渲染引擎为硬件渲染提供了更多的内部结构来支持这个机制。本文将在介绍WebKit中的内部结构之上,同时介绍Chromium又构建的新内部结构,用于该项目中引入的众多纷繁复杂的技术,例如线程化合成器,线程化绘图等等。

## WebKit基础设施

一个RenderLayer对象如果需要后端存储,它会创建一个RenderLayerBacking对象,该对象负责Renderlayer对象所需要的各种存储。正如前面所述,理想情况下,每个RenderLayer都可以创建自己的后端存储,事实上不是所有RenderLayer都有自己的RenderLayerBacking对象。如果一个RenderLayer对象被像样的创建后端存储,那么将该RenderLayer称为合成层(Compositing Layer)。

哪些RenderLayer可以是合成层呢?如果一个RenderLayer对象具有以下的特征之一,那么它就是合成层:

1.      RenderLayer具有CSS 3D属性或者CSS透视效果。

2.      RenderLayer包含的RenderObject节点表示的是使用硬件加速的视频解码技术的HTML5 ”video”元素。

3.      RenderLayer包含的RenderObject节点表示的是使用硬件加速的Canvas2D元素或者WebGL技术。

4.      RenderLayer使用了CSS透明效果的动画或者CSS变换的动画。

5.      RenderLayer使用了硬件加速的CSSfilters技术。

6.      RenderLayer使用了剪裁(clip)或者反射(reflection)属性,并且它的后代中包括了一个合成层。

7.     RenderLayer有一个Z坐标比自己小的兄弟节点,该节点是一个合成层。

至于为什么这么做,不外乎两个原因,第一当然是合并一些RenderLayer层,这样减少内存的使用量,其二是在合并之后尽量减少合并带来的重绘性能和处理上的困难,其三同时对于那些使用单独层能够显著提升性能的RenderLayer对象,继续使用这些好处,例如使用WebGL技术的canvas元素。

每个合成层都有一个RenderLayerBacking,RenderLayerBacking负责管理RenderLayer所需要的所有后端存储,因为后端存储可能需要多个存储空间。在WebKit中,存储空间使用类GraphicsLayer来表示。

下图就是WebKit构建的从RenderLayer树到RenderLayBacking树,再到GraphicsLayer树,并给出这些硬件加速基础设施的对应关系。在RenderLayer树中的第四个节点没有创建RenderLayerBacking对象,因为不符合上面的创建条件,而对于每个RenderLayerBacking对象,它也至少需要一个GraphicsLayer对象,当然也可能需要多个,图中的RenderLayerBacking分别需要2个,1个或者4个GraphicsLayer对象,这些对象分别表示什么呢?

为什么一个RenderLayerBacking对象需要这么多层呢?原因有很多,例如是需要将滚动条独立开来称为一个层,需要前景层、背景层等,需要两个容器层来表示RenderLayer对应的Z坐标为正数的子女和Z坐标负数的子女,将可能需要滚动的内容建立新层,还有剪裁层和反射层,那么这些层次是如何组织并且它们的绘制顺序是如何呢?上图中的GraphicsLayer树状结构按照一定顺序,具体可以参考于Chromium工程师的文档”Compositing in Blink / WebCore: FromWebCore::RenderLayer to cc:Layer”,图中每个层就是一个GraphicsLayer对象,对于某个RenderLayerBacking对象来说,其中主层是肯定存在的,其它层则不一定存在,因为不是每个RenderLayer对象都需要用到它们。 这其中还有众多的其它层,这里不一一介绍了。

## Chromium基础设施

GraphicsLayer是对一个渲染后端存储的抽象,同众多其它WebKit所定义的抽象类一样,在WebKit移植中,它还需要具体的实现类来支持该类提供的功能。为了完成这一功能,Chromium提供了更为复杂的设施类,这一节主要介绍从GraphicsLayer类到合成器这一过程中所设计的众多内部结构。

下图中描述了从WebCore中同移植无关的GraphicsLayer到之后Chromium移植及Chromium浏览器所设计的Chromium合成器的LayerImpl类这一过程,读者可以看到,中间有好几层,原因在于抽象和合成机制的复杂性,以及性能等众多方面的考虑,从上到下主要类依次是:

GraphicsLayerChromium:GraphicsLayer的子类,实现了GraphicsLayer需要的一个功能,并且加入了Chromium的所需信息。

WebLayer:WebKit的Chromium移植的抽象接口类,它被GraphicsLayerChromium等调用,主要目的是将Chromium的实际后端存储类抽象出来,以便WebCore使用它们。

WebLayerImpl:WebLayer类的实现类,具体作用是将合成器的层能力暴露出来,跟Layer类一一对应。

Layer:合成器的层表示类,是Chromium合成器的接口类,用于表示合成器的合成层,它会形成一颗合成树。

LayerImpl:同Layer对象一一对应,是实际的实现类,包含有后端存储,可能更Layer树在不同的线程,具体在后面介绍。

由上面介绍可以看出,这个过程基本上就是各种类的映射,从GraphicsLayer类到LayerImpl类,目的是将WebKit的合成层映射到合成器中的合成层,合成器最终合成这些层。合成过程在合成器小节中介绍。

## Chromium合成器

合成器的作用就是合成多个合成层,所以它的输入是多个待合成的合成层,每个层都有一些属性(例如3D变形等)。它的输出就是一个后端存储,例如是一个GPU的纹理缓冲区。

Chromium合成器是一个独立并且复杂的模块,顾名思义,它的作用是合成网页划分后的合成层,但是,这里的合成器同网页没有必然的绑定关系,它既可以合成网页,也可合成用户界面,或者多个标签页。其实,按照笔者的理解,如果你的项目中需要合成器,可以尝试移植该合成器为自己所用,当然,该合成器有一些依赖关系需要解除,难度也很大,这些都是题外话。

在架构设计上,合成器采用将表示和实现分离开的原则,也就是前面介绍合成器Layer层(同GraphicsLayer类一一对应)同具体合成器所要合成的操作分离的原则,下图描述了这一思想。WebKit中对合成层的各种设置,最后都使用Layer树来表示,里面包含3D变形、剪裁等属性,但是将这些属性应用到后端存储并合成这一过程并不是在Layer树中进行,而是将这些功能委托LayerImpl树来完成,两者之间通过代理来同步。Layer树所有的信息都会复制到LayerImpl树中,代理的作用是协调和同步两者之间的这些操作。

上图中描述的Layer树工作在主线程,但是LayerImpl树在实现部分的线程,这里可以它理解为就是工作在主线程也可是是单独的一个线程,两者在Chromium中目前都被使用。实现部分作为单独一个线程是在Renderer进程中用来合成网页的时候,通常也称为合成器(compositor)线程,后者也称为线程化合成(threaded compositing)。在Chrome的Android版本,合成实现部分则是在主线程,目的是同浏览器界面的合成,称为线程内合成(in-thread compositing)。

在目前的Chromium合成器中,具体的工作非常复杂,例如还有线程化绘图(impl side painting),远远超出了文章"Chromium硬件加速合成"章节中介绍的合成器过程,希望以后可以在专门的章节中来介绍它们。

## 参考资料

1. https://docs.google.com/presentation/d/1dDE5u76ZBIKmsqkWi2apx3BqV8HOcNf4xxBdyNywZR8/edit?pli=1#slide=id.g9ade3ed5_017

By yongsheng@chromium.org

理解WebKit和Chromium: 硬件加速之RenderLayer树到合成树的更多相关文章

  1. 理解WebKit和Chromium(电子书)

    前言   基础篇 WebKit, WebKit2, Chromium和Chrome介绍 WebKit和Blink WebKit和Chromium代码目录结构介绍 WebKit和Chromium功能模块 ...

  2. Chromium硬件加速渲染的UI合成过程分析

    在Chromium中.Render端和WebGL端绘制出来的UI终于是通过Browser端显示在屏幕上的.换句话说.就是Browser端负责合成Render端和WebGL端的UI.这涉及到不同Open ...

  3. 理解WebKit和Chromium: Android 4.4 上的Chromium WebView

    转载请注明原文地址:http://blog.csdn.net/milado_nju ## 概述 相信读者已经注意到了,在最新的Android 4.4 Kitkat版本中,原本基于Android Web ...

  4. 理解WebKit和Chromium: Chromium WebView和Chrome浏览器渲染机制

    转载请注明原文地址:http://blog.csdn.net/milado_nju ## 数据对比 前面介绍过Chromium WebView的时候,说过有关ChromiumWebView同Chrom ...

  5. 理解WebKit和Chromium: 调试Android系统上的Chromium

    转载请注明原文地址:http://blog.csdn.net/milado_nju 1. Android上的调试技术 在Android系统上,开发人员能够使用两种不同的语言来开发应用程序,一种是Jav ...

  6. 理解WebKit和Chromium: JavaScript引擎简介

    转载请注明原文地址:http://blog.csdn.net/milado_nju 1. 什么是JavaScript引擎 什么是JavaScript引擎?简单来讲,就是能够提供执行JavaScript ...

  7. 【转】理解WebKit和Chromium: JavaScript引擎简介

    转载请注明原文地址:http://blog.csdn.net/milado_nju1. 什么是JavaScript引擎什么是JavaScript引擎?简单来讲,就是能够提供执行JavaScript代码 ...

  8. 理解WebKit和Chromium: Chromium插件和扩展基础

    转载请注明原文地址:http://blog.csdn.net/milado_nju ##概述 插件和扩展是一种扩充浏览器功能的技术,在之前我们介绍过NPAPI插件技术,在Chromium中,远远不只是 ...

  9. 理解WebKit和Chromium: 网页渲染的基本过程

    转载请注明原文地址:http://blog.csdn.net/milado_nju ## 概述 前面介绍了一些渲染引擎的功能,包括网络,资源加载,DOM树,RenderObject树等等,但是,给人以 ...

随机推荐

  1. python的模块与包的导入

    类似于C语言的包含头文件去引用其他文件的函数,python也有类似的机制,常用的引入方法有以下 import 模块名 #模块名就是py文件名 #使用这种方法以后调用函数的时候要使用模块名.函数名()这 ...

  2. page1

    1.1 常用的客户端技术:HTML. CSS. 客户端脚本技术 1.2 常用的服务器端技术:CGI .ASP .PHP (一种开发动态网页技术).ASP.NET(是一种建立动态web应用程序的技术,是 ...

  3. Dubbo框架应用之(一)--服务体系

    Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成,也是一个非常全面的SOA基础框架.其是阿里巴巴SO ...

  4. 初识Spark2.0之Spark SQL

    内存计算平台spark在今年6月份的时候正式发布了spark2.0,相比上一版本的spark1.6版本,在内存优化,数据组织,流计算等方面都做出了较大的改变,同时更加注重基于DataFrame数据组织 ...

  5. Android简易实战教程--第四十七话《使用OKhttp回调方式获取网络信息》

    在之前的小案例中写过一篇使用HttpUrlConnection获取网络数据的例子.在OKhttp盛行的时代,当然要学会怎么使用它,本篇就对其基本使用做一个介绍,然后再使用它的接口回调的方式获取相同的数 ...

  6. 【Unity Shader】Unity Chan的卡通材质

    写在前面 时隔两个月我终于来更新博客了,之前一直在学东西,做一些项目,感觉没什么可以分享的就一直没写.本来之前打算写云彩渲染或是Compute Shader的,觉得时间比较长所以打算先写个简单的. 今 ...

  7. 关于在arm裸板编程时使用printf问题的解决方法

    在ARM裸板驱动编程中,是不允许程序直接调用C库程序的.为什么呢?因为此时kernel还没有被加载,所以在封装在kernel层的C库的API是用不了的,那怎么办? 在开发过程中,printf的功能我不 ...

  8. Effective C++ ——实现

    条款26:尽可能延后变量定义式的出现时间 当你定义一个变量的时候就要保证这个变量能够在程序中使用到,不要定义无意义的变量,这样就要求我们最好是在变量使用到的时候才做定义,因为如果一个变量定义了却不使用 ...

  9. 4.2、Android Studio压缩你的代码和资源

    为了让你的APK文件尽可能的小,你需要在构建的时候开启压缩来移除无用的代码和资源. 代码压缩可在ProGuard中使用,可以检测和清除无用的类,变量,方法和属性,甚至包括你引用的库.ProGuard同 ...

  10. Servlet之cookie处理

    Cookies 通常设置在 HTTP 头信息中(虽然JavaScript 也可以直接在浏览器上设置一个 Cookie).设置 Cookie 的 Servlet 会发送如下的头信息: HTTP/1.1 ...