请选择 进入手机版 | 继续访问电脑版
Mozilla

火狐社区

登录    注册

用新浪微博连接 QQ互联

WebRender:让网页渲染如丝顺滑(上)

yingliu Mozilla员工 发表于 2017-10-25 17:33:22 | 显示全部楼层 [复制链接]
1 3424
本帖最后由 yingliu 于 2017-10-25 17:54 编辑

Firefox Quantum 发布在即。它带来了许多性能改进,包括从 Servo 引入的[极速 CSS 引擎]。

但 Servo 中的很大一块技术尚未被 Firefox Quantum 引入,虽然已经为期不远。这就是 WebRender,它是 Quantum Render 项目的一部分,正被添加到 Firefox 中。


WebRender 以极速著称,但它所做的并非加速渲染,而是使渲染结果更加平滑。

依靠 WebRender,我们希望应用程序以每秒 60 帧(FPS)乃至更快的速度运行:无论显示器有多大,页面每帧发生多少变化。这是可以做到的。在 Chrome 和当前版本的 Firefox 中,某些页面卡到只有 15 FPS,而[使用 WebRender 则能达到 60 FPS。

WebRender 是如何做到这些的呢?它从根本上改变了渲染引擎的工作方式,使其更像 3D 游戏引擎。

一起来看看这话怎么说。

## 渲染器的工作

在[关于 Stylo 的文章]中,我讨论了浏览器如何将 HTML 和 CSS 转换为屏幕上的像素,并提到大多数浏览器通过五个步骤完成此操作。

可以将这五个步骤分成两部分来看。前一部分基本上是在构建计划:渲染器将 HTML 和 CSS 以及视口大小等信息结合起来,确定每个元素应该长成什么样(宽度,高度,颜色等)。最终得到的结果就是帧树 (frame tree),又称作渲染树(render tree)。

另一部分是绘制与**(painting and compositing),这正是渲染器的工作。渲染器将前一部分的结果转换成显示在屏幕上的像素。



对同一个网页来说,这个工作不是只做一次就够,而必须反复进行。一旦网页发生变化(如某个 div 发生切换 ),浏览器需再次经历这当中的很多步骤。



即便页面并未发生变化(如页面滚动,或某些文本高亮),浏览器仍需进行第二部分中的某些步骤,接着在屏幕上绘制新的内容。



想要滚动、动画等操作看起来流畅,必须以 60 帧每秒的速度进行渲染。

每秒帧数(FPS)这个术语,也许你早有耳闻,但可能不确定其意义。想象你手上有一本手翻书(Flip Book)。一本画满静态绘画的书,用手指快速翻转,画面看起来就像动起来了。

为了使这本手翻书的动画看起来平滑,每秒需要翻过 60 页。



这本书的是由图纸制成的。纸上有许许多多的小方格,每个方格只能填上一种颜色。

渲染器的工作就是给图纸中的方格填色。填满图纸中的所有方格,一帧的渲染就完成了。

当然,计算机当中并不存在真实的图纸。而是一段名为帧缓冲区(frame buffer)的内存。帧缓冲区中的每个内存地址就像图纸中的一个方格...它对应着屏幕上的像素。浏览器将使用数字填充每个位置,这些数字代表 RGBA(红、绿、蓝以及 alpha 通道)形式的颜色值。



当显示器需要刷新时,将会查询这一段内存。

多数电脑显示器每秒会刷新 60 次。这就是浏览器尝试以每秒 60 帧的速度渲染页面的原因。这意味着浏览器有16.67 ms 的时间来完成所有工作(CSS 样式,布局,绘制),并使用像素颜色填充帧缓冲区内存。两帧之间的时间(16.67ms)被称为帧预算(frame budget)。

有时你可能听到人们谈论丢帧的问题。所谓丢帧,是系统未能在帧预算时间内未完成工作。缓冲区颜色填充工作尚未完成,显示器就尝试读取新的帧。这种情况下,显示器会再次显示旧版的帧信息。

丢帧就像是从手翻书中撕掉一个页面。这样一来,动画看上去就像消失或跳跃一样,因为上一页和下一页之间的转换页面丢失了。



因此要确保在显示器再次检查前将所有像素放入帧缓冲区。来看看浏览器以前是如何做的,后来又发生了哪些变化。从中可以发现提速空间。

## 绘制、合 成简史

注意:绘制与合 成是不同渲染引擎之间最为不同的地方。单一平台浏览器(Edge 和 Safari)的工作方式与跨平台浏览器(Firefox 和 Chrome)有所不同。

即便是最早的浏览器也有一些优化措施,使页面渲染速度更快。例如在滚动页面的时候,浏览器会保留仍然可见的部分并将其移动。然后在空白处中绘制新的像素。

搞清楚发生变化的内容,只更新变动的元素或像素,这个过程称为失效处理(invalidation)。

后来,浏览器开始应用更多的失效处理技术,如矩形失效处理(rectangle invalidation)。矩形失效处理技术可以找出屏幕中包围每个发生改变的部分的最小矩形。然后只需重绘这些矩形中的内容。

页面变化不大时,这确实能够减少大量工作。比如说,光标闪动。



但如果页面大部分内容发生变化,这就不够用了。所以又出现了处理这些情况的新技术。

### 图层与合 成介绍

当页面的大部分发生变化时,使用图层(layer)会方便很多...至少在某些情况下是如此。

浏览器中的图层很像 Photoshop 中的图层,或手绘动画中使用的洋葱皮层。大体说来就是在不同图层上绘制不同元素。然后可以调整这些图层的相对层级关系。

这些一直以来就是浏览器的一部分,但并不总是用于加速。起初,它们只是用来确保页面正确呈现。它们对应于堆叠上下文(stacking contexts)。

例如一个半透明元素将在自己的堆叠上下文中。这意味着它有自己的图层,所以你可以将其颜色与下面的颜色混合。一帧完成后,这些图层就被丢弃。在下一帧中,所有图层将再次重绘。



但是,这些图层中的东西在不同帧之间常常没有变化。想一下那种传统的动画。背景不变,只有前景中的字符发生变化。保留并重用背景图层,效率会更高。

这就是浏览器所做的。它保留了这些图层。然后浏览器可以仅重绘已经改变的图层。在某些情况下,图层甚至没有改变。它们只需要重新排列:例如动画在屏幕上移动,或是某些内容发生滚动。



组织图层的过程称为合 成。合 成器(compositor)从这两部分开始:

*   源位图:背景(包括可滚动内容所占的空白框)和可滚动内容本身

*   目标位图:屏幕所显示的位图

首先,合 成器将背景复制到目标位图中。

然后找到可滚动内容中应该展示的部分。将该部分复制到目标位图。



这减少了主线程的绘制量。但这意味着主线程需要花费大量时间进行合 成。而还有很多工作在主线程上争夺时间。

以前我已经谈过这个问题,主线程有些像一个全栈开发者。它负责 DOM,布局和 JavaScript。并且还负责绘制与合 成。



主线程花费多少毫秒进行绘制、合 成,就有多少毫秒无法用于 JavaScript 和布局。


而另一部分硬件正在闲置,没有多少工作要做。这个硬件是专门用于图形的。它就是 GPU。自 90 年代末以来,游戏一直在使用 GPU 加速渲染帧。自那以后,GPU 日益强大。



### GPU 加速合 成

所以浏览器开发者开始把事情转移给 GPU 来处理。

有两项任务可以转交给 GPU:

1.  图层绘制

2.  图层合 成

将绘制工作交给 GPU 可能比较棘手。所以在多数情况下,跨平台浏览器依然通过 CPU 进行绘制。

但 GPU 可以很快完成合 成工作,转移过来比较简单。



一些浏览器在这种并行方法上走得更远,直接在 CPU 上添加了一个合 成器线程。由它管理 GPU 中发生的合 成工作。这意味着如果主线程正在执行某些操作(如运行 JavaScript),则合 成器线程仍然可以处理其他工作,如在用户滚动时滚动内容。



这样就将所有合 成工作从主线程中移出。尽管如此,它仍然在主线程上留下了大量的工作。图层需要重绘时,主线程需要执行绘制工作,然后将该图层转移给 GPU。

有些浏览器将绘制工作移动到另一个线程中(目前 Firefox 正致力于此)。但将绘制这点工作转移到 GPU 上,速度会更快。


(未完待续!由于发帖字数限制,又只能分为上中下集了,前往中集


## 关于作者
Lin Clark (http://code-cartoons.com)
Lin 是 Mozilla 开发者关系团队的工程师。她专注于 JavaScript,WebAssembly,Rust 和 Servo,以及绘制代码漫画。

本文转载自:[众成翻译](http://www.zcfy.cc)
译者:[文蔺](http://www.zcfy.cc/@wemlin)
审校:[huangxiaolu](http://www.zcfy.cc/@huangxiaolu)
链接:[http://www.zcfy.cc/article/4386]
原文:[https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank]
隐元 老狐狸
发表于 2017-10-26 06:56:57 | 显示全部楼层
mozilla拥有最先进的编程语言:rust!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发新帖
论坛更多 »
热门活动更多 »
  • 量子火狐中国社区见面会 Firefox Quantum Fan Meeting[北京]

    立即参与
火狐微信
快速回复 返回顶部 返回列表