ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

读《webkit技术内幕》了解浏览器内核六——硬件加速机制

读《webkit技术内幕》了解浏览器内核六——硬件加速机制 前面了解到浏览器有软件渲染和GPU硬件加速渲染以及软件绘图的合成化渲染等方式其中硬件加速渲染算是比较重要的不过我只是了解了它的一些优缺点至于浏览器到底如何实现硬件加速机制的我还不知道所以本篇继续跟着书中讲解来了解下硬件加速机制。硬件加速机制其实就是指使用GPU的硬件能力来帮助渲染网页。依然采用问题形式。问题前一篇提到过在分层的网页结构中GPU硬件加速渲染会提供相应的后端存储而网页往往较为复杂可能会分成很多层会有很多 RenderLayer 对象那么GPU是不是要给所有的RenderLayer 对象都进行后端存储那是理想情况现实中不一定。主要原因是实际中的硬件能力和资源有限。考虑到资源节省等问题硬件加速机制是如何去优化、去渲染网页呢主要是三件事WebKit决定将哪些 RenderLayer 对象组合在一起形成一个有后端存储的新层这一新层不久后会用于之后的合成作者将其称为合成层。每个新层都有一个或多个后端存储这里的后端存储可能是 GPU的内存。对于一个 RenderLayer 对象如果它没有后端存储的新层那么就使用它父亲所使用的的 合成层。将每个合成层包含的这些 RenderLayer 内容绘制在 合成层 的后端存储中这里的绘制可以是软件绘制也可以是硬件绘制。由合成器将多个合成层合成起来形成网页的最终可视化结果实际就是一张图片。合成器是一种能够将多个合成层按照这些层的前后顺序、合成层的 3D 变形等设置而合成一个图像结果的设施。那么哪些 RenderLayer 对象可以组合成 合成层 呢具有以下等特征RenderLayer具有CSS 3D属性或者CSS透视效果RenderLayer包含的RenderObject节点表示的是使用硬件加速的视频解码技术的 HTML5video元素RenderLayer包含的RenderObject节点表示的是使用硬件加速的 Canvas 2D元素或者WebGL技术RenderLayer使用了CSS透明效果的动画或者CSS变换的动画RenderLayer使用了硬件加速的CSS Filters技术RenderLayer使用了裁剪(Clip)或者反射(Reflection)属性并且它的后代中包括一个合成层RenderLayer有一个Z坐标比自己小的兄弟节点且该节点是一个合成层了解了以上的知识后能说说硬件渲染的过程吗由于涉及到不少内部类和方法考虑到项目一直在迭代可能书上所讲的有所改变所以这里提炼下大致过程尽量不涉及具体类和方法名。1.首先WebKit确定并计算合成层检查RenderLayer对象是否为合成层是的话为其创建后端存储对象RenderLayerBacking根据重新更新的合成层来更改合成层树并修改后端存储对象的设置信息2.其次遍历和绘制每一个合成层可能存在以下四种情况第一种情况HTMLDocument节点 需要一个用于2D图形的图形上下文对象同软件渲染非常类似但递归过程不同。每个RenderLayer对象被绘制到祖先链中最近的合成层。第二种情况使用 CSS 3D变形的合成层。第三种情况使用WebGL技术的Canvas元素所在的合成层它的绘制由javascript操作完成并且使用了3D图形上下文。第四种情况类似使用了硬件加速的视频元素所在的合成层该层的内容其实是由视频解码器来绘制而后通过定时器或者其他通知机制来告诉WebKit该层内容发生改变.3.最后渲染引擎将所有绘制完的合成层合成起来前面介绍到webkit中会有3D和2D图形上下文Chromium是不是也一样呢内部调用栈是什么样的呢webkit中2D图形上下文对应Chromium的Skia画布(canvas)具体调用栈可以看图了解下即可。结合以前介绍的进程灯知识GPU硬件加速渲染是在哪个进程上执行的是Renderer进程吗对于使用多进程模型的Blink内核的浏览器来说不是的GPU硬件加速渲染的操作会交由GPU进程负责。多进程模型下是如何实现跨进程的硬件加速渲染的这个很复杂依靠Renderer进程的主要类和GPU进程的主要类它们彼此内部的实现。涉及到太多类不展开建议结合项目代码去看。总结就是GPU进程处理一些命令后会向Renderer进程报告自己当前状态Renderer进程通过检查状态信息和自己期望结果来确定是否满足自己的条件。值得注意的是GPU进程最终绘制的结果不再像软件渲染那样通过共享内存传递给Browser进程而是直接将页面内容绘制在浏览器的标签窗口。本篇第一个问题下的回答就提到过合成器Chromium的合成器是如何实现的呢在架构设计上采用了表示和实现分离原则。图例需要注意Layer树工作的主线程实际指的是渲染引擎工作的线程不一定是Renderer进程的主线程。但是LayerImpl树工作的实现部分的线程既可以是主线程也可以是单独的线程。实现部分如果是一个单独的线程那么可以称为合成器线程也叫线程化合成。Chromium合成器的组成部分是什么样的事件处理部分。主要接收WebKit或者其他的用户事件例如网页滚动、放大缩小等事件这些事件会请求合成器重新绘制每一个合成层然后合成器再合成这些层的绘制结果合成层的表示和实现。主要定义各种类型的合成层包括它们的位置、滚动位置、颜色等属性合成层组成两种类型的树以及它们之间的同步等机制合成调度器(Scheduler)主要调度来自用户的请求它包括一个状态用于调度当前队列中需要执行的请求目的当然是协调合成层的绘制和合成、树的同步等操作。调度器是在合成器线程中的因而不能访问主线程中的资源合成器的输出结果。结果可以是一个GPU Surface或者一个CPU存储空间。各种后端存储等资源支持动画和3D变形这些功能所需要的基础设施拓展介绍绘制HTML元素和图片元素所生成的合成层其后端存储会被瓦片化为什么会使用瓦片化的后端存储呢有以下三点好处DOM树中的html元素所在的层可能会比较大因为网页高度很大如果只是使用一个后端存储的话那么需要一个很大的对象但是实际的GPU硬件可能只支持非常有限的纹理大小在一个比较大的合成层中可能只是其中一部分发生变化根据之前的介绍需要重新绘制整个层这样必然产生额外的开销使用瓦片化的后端存储就只需要重绘一些存在更新的瓦片当层发生滚动时一些瓦片可能不再需要然后WebKit需要一些新的瓦片来绘制新的区域这些大小相同的后端存储很容易重复利用简洁漂亮了解完合成器知识后能简要说说合成过程吗主要有四个步骤都是由调度器调度创建输出结果的目标对象Surface也就是合成结果的存储空间开始一个新的帧包括计算滚动和缩放大小、动画计算、重新计算网页的布局、绘制每个合成层等将Layer树中包含的这些变动同步到LayerImpl树中合成LayerImpl树中各个层并交换前后帧缓冲区完成一帧的绘制和显示动作可以看看图了解下前面介绍过2D绘图也可以进行硬件加速如何做到的呢首先什么是2D绘图的硬件加速2D绘图本身是使用2D的图形上下文一般使用软件方式来绘制它们也就是光栅化。使用GPU来绘制2D图形的方法称为2D图形的硬件加速机制。2D图形的硬件加速机制有两种应用场景2D图形上下文——网页基本元素绘制(HTML基本标签)canvas 2D2D图形上下文是如何进行硬件加速的呢依靠Skia图形库。当需要启动硬件加速时只需要对SkCanvas对象进行的相应设置即可。具体内部类和方法建议看书和代码。Canvas 2D是如何进行硬件加速的呢比较复杂涉及太多内部类建议结合项目代码和书去看。简单来说在Chromium中canvas 2D进行GPU硬件加速绘图时会创建一个SkDeferredCanvas对象该对象采用延迟机制来绘制2D图形。然后该对象需要SkGpuDevice来将2D绘图操作转换为使用3D图形上下文来绘制。WebGL是如何实现的​​​​​​​同样设计太多内部类建议看书。粗略提下吧Chromium中WebGL工作过程分成三个阶段对象的初始化构建RenderLayer、WebLayer、CC::Layer等对象在DOM树构建之后检查CSS样式变化时才会触发3D绘图
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进