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

火狐社区

登录    注册

用新浪微博连接 QQ互联

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

yingliu Mozilla员工 发表于 2017-10-25 17:40:49 | 显示全部楼层 [复制链接]
3 2713
本帖最后由 yingliu 于 2017-10-25 17:53 编辑

《WebRender:让网页渲染如丝顺滑(中)》

## WebRender 如何利用 GPU


回过头再看下浏览器渲染网页的步骤。这里将产生两个变化。



1.  绘制与**之间不再有区别。它们都是同一步骤的一部分。GPU 根据传递给它的图形 API 命令同时执行它们。

2.  布局步骤将产生一种不同的数据结构。之前是帧树(或 Chrome 中的渲染树)。现在将产生一个显示列表(display list)。

显示列表是一组高级绘图指令。它告诉我们需要绘制什么,并不指定任何图形 API。

每当有新东西要绘制时,主线程将显示列表提供给 RenderBackend,这是在 CPU 上运行的 WebRender 代码。

RenderBackend 的工作是将这个高级绘图指令列表转换成 GPU 需要的绘图调用,这些绘图调用被分在同一批次,加快运行速度。



然后,RenderBackend 线程将把这些批次传递给**器线程,**器线程再将它们传递给 GPU。

RenderBackend 线程传递给 GPU 的绘图调用需要尽可能快运行。它为此使用了几种不同的技术。

### 从列表中删除任何不必要的形状(早期剔除)

节省时间的最好办法是什么都不做。

首先,RenderBackend 可以减少显示列表项目。它会识别哪些项目将真正出现在屏幕上。为此,它将查看一些东西,如每个滚动盒的滚动距离。

如果形状的某些部分在盒子内,则该形状将被包括在需要绘制的列表中。否则将被删除。这个过程叫做早期剔除。



### 最小化中间纹理数量(渲染任务树)

现在有了一个树状结构,其中只包含将要用到的形状。这个树被组织成此前提过的堆叠上下文。

CSS filter 和堆叠上下文等这些效果,让事情变得复杂了。假设有一个透明度为 0.5 的元素,该元素包含子元素。你可能觉得每个子元素都将是透明的……但实际上整个组才是透明的。



因此需要先将该组渲染为一个纹理,每个子元素都是不透明的。然后,将子元素加入到父元素中时,可以更改整个纹理的透明度。

这些堆叠上下文可以嵌套...该父元素可能是另一个堆叠上下文的一部分。这意味着它必须被渲染成另一个中间纹理……

为这些纹理创建空间代价不菲。我们想尽可能将事物分组到相同的过渡期纹理。

为了帮助 GPU 执行此操作,需要创建一个渲染任务树。有了它,就能够知道在其他纹理之前需要创建哪些纹理。任何不依赖于其他纹理的纹理都可以在首次创建,这意味着它们可以与那些中间纹理中组合在一起。

所以在上面的例子中,我们先输出 box shadow 的一个角。(实际比这更复杂一点,但这是要点)。



第二遍的时候,可以将这个角通过镜像放置到盒子的各个部分。然后就可以完全不透明地渲染该组。



接下来,我们需要做的就是改变这个纹理的不透明度,并将其放在需要输入到屏幕的最终纹理中。



通过构建这个渲染任务树,可以找出需要使用的离屏渲染目标的最小数量。这很好,前面已经提到过,为这些渲染目标纹理创建空间的代价不菲。

这也有利于分批处理。

### 绘制调用分组(批处理)


前面已经提到过,需要创建一定量的批处理,每个批处理中包括大量形状。

注意,创建批处理的方式真的能影响速度。同一批次中的形状数量要尽可能多。这是由几个原因决定的。

首先,当 CPU 告诉 GPU 进行绘图调用时,CPU 必须做很多工作。比如,启动 GPU,上传着色器程序和测试硬件 bug 等。并且当 CPU 进行这项工作时,GPU 可能是空闲的。

其次,改变状态是会产生代价的。假设你需要在批处理之间更改着色器程序。在典型的 GPU 上,你需要等到所有内核都使用当前的着色器完成工作后。这被称管道清空(draining the pipeline)。管道清空后,其他核心才会处于闲置状态。



因此,批处理包含的东西要尽可能多。对于典型的 PC,每帧需要有100 次或更少的绘图调用,每次调用中有数千个顶点。这样就能充分利用并行性。

从渲染任务树可以找出能够批处理的内容。

目前,每种类型的图元都需要一种着色器。例如边框着色器,文本着色器,图像着色器。



我们认为可以将很多着色器结合起来,这样就能够增加批处理容量。但目前这样已经相当不错了。

已经可以准备将它们发送给 GPU 了。但其实还可以做一些排除工作。

### 减少像素着色(Z-剔除)

大多数网页中都有大量相互重叠的形状。例如,文本框位于某个带有背景的 div 之中,而该 div 又在带有另一个背景的 body 中。

GPU 在计算每个像素的颜色时,能够计算出每个形状中的像素颜色。但只有顶层才会显示。这被称为 overdraw,它浪费了 GPU 时间。



所以我们可以先渲染顶部的形状。绘制下一个形状时,遇到同一像素,先检查是否已经有值。如果有值,则跳过。



不过这有一点点问题。当形状是半透明的时候,需要混合两种形状的颜色。为了让它看起来正确,需要从里向外绘制。

所以需要把工作分成两道。首先做不透明的一道工作。由表及里,渲染所有不透明的形状。跳过位于其他像素背后的像素。

然后处理半透明形状。工作由内向外进行。如果半透明像素落在不透明像素的顶部,则会混合到不透明的像素中。如果它会落在不透明形状之后,则忽略计算。

将工作分解为不透明和 alpha 通道两部分,跳过不需要的像素计算,这个过程称为 Z-剔除(Z-culling)。

这看起来只是一个简单的优化,但对我们来说已经是很大的成功了。在典型的网页上,该工作大大减少了我们需要处理的像素数量,目前我们正在研究如何将更多的工作转移到不透明这一步。

到目前为止,我们已经准备好了一帧的内容。我们已经尽可能地减少了工作。

### 准备绘制

我们准备好启动 GPU 并渲染各个批次了。



### 警告:不是一切都靠 GPU

CPU 仍然需要做一些绘制工作。例如,我们仍然使用 CPU 渲染文本块中的字符(称为字形,glyphs)。在 GPU 上也可以执行此操作,但是很难获得与计算机在其他应用程序中呈现的字形相匹配的像素效果。所以 GPU 渲染的字体看起来会有一种错乱感。我们正在尝试通过 [Pathfinder 项目](https://github.com/pcwalton/pathfinder)将字形等工作转移到 GPU 上。

这些内容目前是被 CPU 绘制成位图的。然后把它们上传到 GPU 的纹理缓存中。这个缓存在不同帧之间被保留,因为它们通常不会改变。

虽然这种绘制工作是由 CPU 完成的,但速度仍有提升空间。例如,使用某种字体绘制字符时,我们会将不不同的字符分割开,使用不同内核分别渲染。这和 Stylo 用来并行计算样式的技术是相同的……参见[这里]。

## WebRender 接下来的工作

在 Firefox Quantum 发布之后的若干版本后,WebRender 有望在 2018 年作为Quantum Render 项目的一部分,出现在 Firefox 中。这将使当今的网页运行更顺畅。随着屏幕上的像素数量的增加,渲染性能变得越来越重要,因此 WebRender 还可以让 Firefox 为新一波的高分辨率 4K 显示器做好准备。

但 WebRender 不仅仅适用于 Firefox。它对于正在开展的 WebVR 的工作同样至关重要,在 WebVR 中,需要为在 4K 显示器上以 90 FPS 的速度为每只眼睛渲染不同的帧。

WebRender 的早期版本目前可以通过 Firefox 的 flag 来启用。集成工作仍在进行中,所以性能目前还不如集成工作完成后那么好。如果你想跟进 WebRender 开发,可以关注 GitHub repo,或者关注 Firefox Nightly 的 Twitter,以获得 Quantum Render 项目的更新周报。



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


## 关于作者
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]
310971373 狐狸精
发表于 2017-10-25 21:57:13 | 显示全部楼层
沙发,还是要努力学习新技术的,努力中 。。。。。。
FlamingFox 小狐狸
发表于 2017-10-26 19:52:22 | 显示全部楼层
嗯,不错,这三篇文章写得不错,学习了。这下知道该怎么使用最新版本的火狐了。
RobberPhex 狐狸仔
发表于 4 天前 | 显示全部楼层
那js执行部分的优化有没有在做?

现在浏览器中的js越来越多,提升js执行效率很重要啊。
当然,webextension的功能添加也很重要。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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