6月阅读周·WebKit技术内幕 | 硬件加速机制
背景
去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。
没有计划的阅读,收效甚微。
新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。
这个“玩法”虽然常见且板正,但是有效,已经坚持阅读五个月。
已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》、《你不知道的JavaScript(下卷)》、《数据结构与算法JavaScript描述》。
当前阅读周书籍:《WebKit技术内幕》。
硬件加速机制
硬件加速基础
概念
这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页,因为GPU的作用主要是用来绘制3D图形并且性能特别好,这是它的专长所在,它同软件渲染有很多不同的地方,既有自己的优点,当然也有些不足之处。
为了节省GPU的内存资源,硬件加速机制在RenderLayer树建立之后需要做三件事情来完成网页的渲染。
- WebKit决定将哪些RenderLayer对象组合在一起,形成一个有后端存储的新层,这一新层不久后会用于之后的合成(Compositing),这里称之为合成层(Compositing Layer)。每个新层都有一个或者多个后端存储,这里的后端存储可能是GPU的内存。对于一个RenderLayer对象,如果它没有后端存储的新层,那么就使用它的父亲所使用的合成层。
- 将每个合成层包含的这些RenderLayer内容绘制在合成层的后端存储中,这里的绘制可以是软件绘制也可以是硬件绘制。
- 由合成器(Compositor)将多个合成层合成起来,形成网页的最终可视化结果,实际就是一张图片。合成器是一种能够将多个合成层按照这些层的前后顺序、合成层的3D变形等设置而合成一个图像结果的设施,后面会介绍Chromium合成器的工作原理。
WebKit硬件加速设施
一个RenderLayer对象如果需要后端存储,它会创建一个RenderLayerBacking对象,该对象负责Renderlayer对象所需要的各种存储。正如前面所述,理想情况下,每个RenderLayer都可以创建自己的后端存储,但事实上不是所有RenderLayer都有自己的RenderLayerBacking对象。如果一个RenderLayer对象被WebKit依照一定的规则创建了后端存储,那么该RenderLayer被称为合成层。
每个合成层都有一个RenderLayerBacking,RenderLayerBacking负责管理RenderLayer所需要的所有后端存储,因为后端存储可能需要多个存储空间。在WebKit中,存储空间使用GraphicsLayer类来表示。
管理这些合成层等工作的是RenderLayerCompositor类,这个类可以说是个“大管家”。它不仅计算和决定哪些RenderLayer对象是合成层,而且为合成层创建GraphicsLayer对象。每个RenderView对象包含一个RenderLayerCompositor,这些对象仅在硬件加速机制下才会被创建。RenderLayerCompositor类本身也类似于一个RenderLayerBacking类,也就是说它也包含一些GraphicsLayer对象,这些对象对应的是整个网页所需要的后端存储。
硬件渲染过程
WebKit如何决定哪些层是合成层并为它们分配后端存储的过程。主要包含两个部分,都是RenderLayerCompositor类的函数,一是检查RenderLayer对象是否为合成层,如果是的话,为它们创建后端存储对象RenderLayerBacking;二是根据重新更新的合成层来更改合成层树,并修改后端存储对象的一个设置信息。
WebKit为网页中的5个DOM节点创建RenderLayer对象,分别为HTMLDocument对象、HTMLHtmlElement对象、HTMLDivElement对象、HTMLCanvas对象和HTMLVideo对象。但是,图中只有4个RenderLayerBacking对象,这是因为HTMLHtmlElment对象对应的RenderLayer没有自己的RenderLayerBacking对象,原因是该RenderLayer对象不满足之前所描述的规则。
随着HTML5中不断加入图形和多媒体方面的功能,例如Canvas2D、WebGL、CSS 3D和视频等。
其次,WebKit需要遍历和绘制每一个合成层,也就是每个合成层可能有一个或者多个RenderLayer对象。
在软件渲染过程中,paintLayer函数被递归调用,也就是从RenderLayer根节点开始,直到所有的RenderLayer对象都被遍历为止。
Chromium的硬件加速机制
GraphicsLayer的支持
GraphicsLayer对象是对一个渲染后端存储中某一层的抽象,同众多其他WebKit所定义的抽象类一样,在WebKit移植中,它还需要具体的实现类来支持该类所要提供的功能。为了完成这一功能,Chromium提供了更为复杂的设施类。
框架
在Chromium中,有个比较特别的设计,就是所有使用GPU硬件加速(也就是调用OpenGL编程接口)的操作都是由一个进程(称为GPU进程)负责来完成的,这其中包括使用GPU硬件来进行绘图和合成。Chromium是多进程架构,每个网页的Renderer进程都是将之前介绍的3D绘图和合成操作通过IPC传递给GPU进程,由它来统一调度并执行。在Chrome的Android版本中,GPU进程并不存在,Chrome是将GPU的所有工作放在Browser进程中的一个线程来完成,这得益于结构设计的灵活性。但是本质上,GPU进程和GPU线程并无太大区别。
命令缓冲区
命令缓冲区(Command Buffer)主要用于GPU进程(以后称为GPU服务端)和GPU的调用者进程(且称GPU客户端进程,如Renderer进程、Pepper插件进程)传递GL操作命令。从接口上来讲,这一设计只提供一些基本的接口来管理缓冲区,它并没有对缓冲区的具体方式和命令的类型进行任何限制,不过目前Chromium只有GLES一种实现方式。
现有的实现是基于共享内存的方式来完成的,因而命令是基于GLES编码成特定的格式存储在共享内存中。共享内存方式采用了环形缓冲区(RingBuffer)的方式来管理,这表示内存可以循环使用,旧的命令会被新的命令所覆盖。
总结
本篇进入WebKit高级技术部分,这部分介绍更为复杂和新颖的技术,包括硬件加速机制、JavaScript引擎内部原理、插件和扩展机制、多媒体技术、安全机制、移动技术、调试技术和Web平台。
随着HTML5中不断加入图形和多媒体方面的功能,例如Canvas2D、WebGL、CSS 3D和视频等,这对渲染引擎使用图形库的性能提出了很高的要求。在WebKit渲染基础之上,本章着重描述WebKit为了支持硬件加速机制而引入了哪些内部结构,以及Chromium如何在这些设施上实现了特殊的硬件加速机制,这些机制的引入极大地提升了WebKit引擎的渲染性能。
作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)