丝绸项目

编辑注:这篇文章的早期版本出现在 Mason Chang 的个人博客上。

在过去的几个月里,我一直在致力于丝绸项目,该项目旨在提高整个浏览器的流畅度。 就像Android 的黄油计划一样,其中一部分终于在 Firefox OS 上上线了。 丝绸项目主要做三件事

  1. 将绘制与硬件垂直同步对齐
  2. 根据硬件垂直同步对触摸输入事件进行重采样
  3. 将合成与硬件垂直同步对齐

什么是垂直同步,为什么要使用垂直同步,以及它为什么重要?

垂直同步 (vsync) 发生在硬件显示器在屏幕上显示新帧时。 这个速率由特定硬件设置,但在美国的多数显示器以每秒 60 次的速度运行,即每 16.6 毫秒 (毫秒) 一次。 这就是你听到每秒 60 帧的说法,硬件显示器刷新一次就有一帧。 这在现实中意味着,无论软件中产生了多少帧,硬件显示器每秒最多只能显示 60 帧。

目前,Firefox 模拟每秒 60 帧,并通过一个软件计时器来实现垂直同步,该计时器每 16.6 毫秒调度一次渲染。 然而,软件调度器有两个问题:(a)它很嘈杂,(b)它相对于垂直同步可能在不合适的时机进行调度。

关于噪音,软件计时器比硬件计时器要嘈杂得多。 这会造成微型卡顿,原因有很多。 首先,许多动画都是基于软件调度器生成的用于更新动画位置的时间戳。 如果你曾经使用过requestAnimationFrame,你就会从软件计时器那里获得一个时间戳。 如果你想要平滑的动画,提供给 requestAnimationFrame 的时间戳应该是一致的。 不一致的时间戳会导致不一致和卡顿的动画。 下面是一个图表,显示了软件与硬件垂直同步计时器的均匀性

timer

哇! 使用硬件计时器后,改进很大。 我们得到了更均匀,因此更平滑的时间戳,可以用来键控动画。 这样就解决了问题 (a),软件与硬件中的计时器噪音问题。

对于问题 (b),软件计时器可能会在相对于垂直同步的错误时机进行调度。 无论软件做什么,硬件显示器都会按照自己的时钟刷新。 如果我们的渲染管道在下一个垂直同步之前完成了帧的制作,显示器就会用新内容进行更新。 如果我们没有在下一个垂直同步之前完成帧的制作,就会显示前一帧,从而导致卡顿。 有些渲染函数可能在接近垂直同步时执行,并溢出到下一个时间间隔。 因此,我们实际上引入了更多的潜在延迟,因为帧在下一个垂直同步之前不会显示在屏幕上。 让我们通过图形来观察一下

frames

在时间 0,我们开始制作帧。 例如,假设所有帧的制作时间都是 10 毫秒。 我们的帧预算为 16.6 毫秒,因为我们只需要在下一个硬件垂直同步发生之前完成帧的制作。 由于帧 1 在下一个垂直同步之前 6 毫秒完成(时间 t=16 毫秒),所以一切都顺利,生活很美好。 帧及时制作,硬件显示器会用更新的内容进行刷新。

现在让我们看一下帧 2。 由于软件计时器很嘈杂,我们在下一个垂直同步之前的 9 毫秒开始制作帧(时间 t=32)。 由于我们的帧制作需要 10 毫秒,所以我们实际上在下一个垂直同步之后的 1 毫秒完成了帧的制作。 这意味着在垂直同步编号 2(t=32)时,没有新帧可供显示,所以显示器仍然显示前一帧。 此外,刚刚制作的帧直到垂直同步 3(t=48)才会显示,因为那是硬件更新自身的时候。 这会造成卡顿,因为现在显示器会跳过一帧,并尝试在接下来的帧中进行弥补。 这还会造成一帧额外的延迟,这对游戏来说是不可取的。

垂直同步解决了这两个问题,因为我们得到了更均匀的计时器和更长的帧预算时间来制作新帧。 现在我们知道了什么是垂直同步,我们终于可以继续探讨丝绸项目是什么以及它如何帮助在 Firefox 中创建流畅的体验。

渲染管道

用非常简单的术语来说,Gecko 的渲染管道主要做三件事

  1. 在主线程上绘制/渲染新帧。
  2. 通过 LayerTransaction 将更新的内容发送到合成器。
  3. 合成新内容。

在理想情况下,我们可以在 16.6 毫秒内完成这三个步骤,但这在大多数情况下是不可能的。 步骤 (1) 和 (3) 都在独立的软件计时器上执行。 因此,这三个步骤之间没有真正的同步时钟,它们都是独立的。 它们也与垂直同步无关,因此管道的时间安排与显示器实际用内容更新屏幕的时间无关。 在丝绸项目中,我们将这两个独立的软件计时器替换成了硬件垂直同步计时器。 就我们而言,(2) 不会真正影响结果,但为了完整起见,这里也提到了它。

将绘制与硬件垂直同步对齐

将用于驱动刷新计时器与垂直同步对齐,可以通过两种方式创造流畅度。 首先,许多动画仍然是在主线程上完成的,这意味着任何使用时间戳设置动画位置的动画都应该更加平滑。 这也包括 requestAnimationFrame 动画! 另一个好处是,我们现在对渲染启动时间有了一个非常严格的顺序。 我们不再是在独立的同步偏移量上执行 (1) 和 (3),而是在特定时间启动渲染。

根据垂直同步对触摸输入事件进行重采样

在丝绸项目中,我们可以启用触摸重采样,这可以在跟踪你的手指时改善流畅度。 由于我已经在博客中介绍过触摸重采样,所以我在这里只说几句。 在丝绸项目中,我们终于可以启用它!

将合成与硬件垂直同步对齐

最后,丝绸项目的最后一部分是关于将合成与硬件垂直同步对齐。 合成器将所有绘制的内容合并在一起,形成你在显示器上看到的单幅图像。 在丝绸项目中,所有合成都在硬件垂直同步发生后立即开始。 这实际上带来了一项非常好的额外好处——这里显示的合成时间缩短了

compositeTimes

在火焰设备的设备驱动程序中,有一个全局锁,在接近垂直同步间隔时会被获取。 这个锁可能需要 5-6 毫秒才能获取,这会大大增加合成时间。 然而,当我们在垂直同步后立即启动合成时,获取锁的争用很小。 因此,我们可以节省等待时间,从而大大减少合成时间。 我们不仅获得了更流畅的动画,还获得了更短的合成时间,从而延长了电池寿命。 这真是双赢!

有了这三个部分,我们现在对渲染管道有了很好的严格顺序。 我们在 16.6 毫秒内绘制并向合成器发送更新的内容。 在下一个垂直同步时,我们将合成更新的内容。 在接下来的垂直同步时,帧应该已经完成了渲染管道,并将显示在屏幕上。 保持这种顺序可以减少卡顿,因为我们减少了计时器在错误时机调度每个步骤的可能性。 在没有丝绸项目的当前实现的最佳情况下,一帧可以在单个 16.6 毫秒帧内完成绘制和合成。 这是很棒的。 然而,如果下一帧需要 2 帧才能完成,我们就造成了额外的卡顿,即使管道的任何阶段都没有真正变慢。 将整个管道对齐以创建事件的严格顺序,可以降低错误调度帧的可能性。

master

这是一张没有丝绸项目的渲染管道图。 我们在该配置文件的底部看到了合成器 (3)。 我们在中间看到了绘制 (1),其中可以看到样式、重排、显示列表和光栅化。 我们在顶部看到了垂直同步,用那些橙色的方块表示。 最后,我们在底部看到了层事务 (2)。 最初,当我们启动时,合成器和绘制是不对齐的,因此动画的位置会根据它们是在主线程还是合成器线程上而有所不同。 其次,我们看到合成器时间很长,因为合成器正在等待设备驱动程序中的全局锁。 最后,很难解读任何顺序,或者看到是否存在问题,除非你对事物为何/何时发生有深入的了解。

silk

这是一张包含丝绸项目的相同管道图。 合成器时间短了一点,整个管道只在垂直同步间隔启动。 合成时间缩短了,因为我们在垂直同步间隔的精确时刻启动合成器。 现在清楚地表明了事物应该发生的顺序。 合成器和绘制都以相同的时间戳为键,确保动画更流畅。 最后,有一个明确的指示,只要所有操作都在下一个垂直同步之前完成,一切都会很流畅。

最终,丝绸项目的目的是在 Firefox 和 Web 上创造更流畅的体验。 许多人对该项目做出了贡献。 感谢 Jerry Shih、Boris Chou、Jeff Hwang、Mike Lee、Kartikaya GuptaBenoit Girard、Michael Wu、Ben Turner 和 Milan Sreckovic 帮助实现丝绸项目。

关于 Mason Chang

更多 Mason Chang 的文章…


23 条评论

  1. Tim Hamilton

    很高兴看到丝绸项目取得进展。

    作为 HTML5 游戏和应用程序的设计师,Firefox 的运动质量一直以来都比 Chrome 差,在 Windows 上,IE 也是如此。 希望丝绸项目能让 Mozilla 重新回到领先地位。

    丝绸项目的功能是否有计划在 Win/Linux/Android 上推出,比如在开发者版中?

    2015 年 2 月 3 日 下午 1:55

  2. Zimon Dai

    丝绸项目会移植到桌面端吗?

    2015 年 2 月 3 日 下午 5:11

  3. Scrambler

    嗯,如果这真的能起作用就好了——因为现在,Firefox 在 VSYNC 方面彻底崩溃了。甚至有错误报告显示,人们能够在 Firefox 的 JavaScript 中实现 VSYNC 同步,而 Firefox 在原生代码中却无法实现同步。

    真正的 VSYNC 测试需要在运行在两年前的硬件上通过 http://www.vsynctester.com——因为新硬件的速度掩盖了大量的内部问题!

    为什么?因为仅仅能够精确地渲染到 VSYNC 对齐是毫无意义的——除非这些渲染的帧最终以*独特的* VSYNC 间隔出现在屏幕上。

    2015 年 2 月 4 日 上午 9:23

  4. Mason

    我将首先回答前两个问题:Silk 将在 Windows 和 Linux 上的桌面版发布,并将在 2015 年第二季度末之前在 Nightly 版本中发布。此后 6 周后,它将在 Firefox 开发者版中发布。

    回复 Scrambler:你说得对,只有当帧最终以独特的 VSYNC 间隔显示时,它才会起作用。Silk 能够做到这一点,我们进行合成,这将每 VSYNC 间隔显示一次实际的帧。根据错误 1080869,并且在两年前的机器上测试,我们通过了 Windows 7 上的 vsynctester.com 测试,并且表现出色。

    2015 年 2 月 4 日 上午 11:33

  5. Mason

    哎呀,应该说它即将在 Windows 和 Mac 上的桌面版发布。

    2015 年 2 月 4 日 下午 2:12

  6. Scrambler

    Mason,正如 http://www.vsynctester.com 中所记录的那样,在较新的硬件上运行 vsynctester.com 是毫无意义的(无效测试),因为较新的硬件(即使是只有两年前的硬件)速度非常快,系统速度(主要是 GPU)完全掩盖并隐藏了内部 Web 浏览器计时问题。

    我在较旧的硬件上看到了很多 FF VSYNC 问题,但在较新的硬件上没有看到 VSYNC 问题。

    您需要在 2011 年的硬件上进行测试,该硬件轻松支持数百帧/秒,但 FF 实际上存在 VSYNC 问题。然后,使用 Silk 运行并测试 VSYNC 是否已修复。如果是,那就太好了,但如果不是,那么 VSYNC 问题的真正根本问题和原因还没有得到很好的理解。

    我愿意提供我的系统进行测试,但 Mozilla 在其严苛的内部流程中,没有解决我发现并报告的非常严重的错误,而是决定通过将我的视频驱动程序列入黑名单来“修复”我的错误。FF 现在在我的系统回收站中。IE 和 Chrome 在该系统上运行良好。一位 FF 经理在私人电子邮件中告诉我(作为借口),他们对发现的错误感到震惊,因为它从未在内部预发布测试中出现。但这显然表明,FF 内部没有人对较旧的系统进行 FF 测试(只有较新的系统)。

    唯一真正有效的测试是,找到一个系统,其中“旧方法”失败,但新方法(Silk)修复了问题。您同意吗?

    2015 年 2 月 5 日 上午 8:49

  7. Yggdr5

    @Scrambler
    虽然我可以理解您的沮丧,并且也希望这些 VSYNC 问题最终能够得到解决,但我认为这种消极攻击性和居高临下的态度不会让我们离这个目标更近。
    我喜欢您在 vsynctester 上的工作,以及 Mozilla 在 Project Sync 上的工作。归根结底,你们两个都有类似的目标,那么更紧密的合作是否更有利?

    @Mason
    我很好奇当前的 VSYNC 问题是否也会影响使用 HTML5 播放器播放 YouTube 视频。我在一台机器上遇到很多 VSYNC 问题,但我不知道问题出在哪里。我可以排除 Firefox 吗?

    2015 年 2 月 5 日 下午 1:38

    1. Mason

      @Yggdr5 - 嗯,很有趣。什么类型的 VSYNC 问题,比如撕裂?您可以尝试在其他浏览器(如 IE/Chrome)上运行,看看是否出现相同的问题。如果只是 VSYNC 问题,而不是 Firefox 速度太慢导致的渲染问题,那么 Silk 应该可以解决您的错误。

      2015 年 2 月 6 日 上午 11:27

      1. Ben

        我不是他,但如果他看到跟我一样的东西,那就意味着 60 帧/秒的 HTML5 视频无法正常播放,而在其他浏览器或独立播放器上可以正常播放。

        FPS 测量报告显示 60 帧/秒没问题,但视频显然不流畅。我看不到任何撕裂,所以我想有些帧显示了 33 毫秒,而另一些帧根本没有显示。

        2015 年 2 月 7 日 下午 12:02

        1. Mason

          嗯,这听起来很奇怪。您在什么机器上测试,有什么特定的视频吗?我在我的 Mac 上本地无法复现。

          2015 年 2 月 14 日 下午 2:27

  8. Mason Chang

    我阅读了您的描述,即使在我的新机器上,没有 Silk,Firefox 也会很糟糕地通过测试。动画已经存在卡顿,帧间时间始终是红色的,渲染时间始终非常尖锐。我们甚至在没有 Silk 的情况下,在这台两年前的机器上也无法通过测试。帧间时间并不真正一致。正如您所说,紫色的延迟 setTimeout 非常卡顿,即使在高端 MacBook Pro 上也是如此。正如您所发现的那样,即使在高端硬件上,测试也无法在 Firefox 上通过。

    正如您所说,验证 Silk 的唯一真正方法是查看它在当前测试失败的系统上是否更好。当前测试几乎在我的每台机器上都无法在 Firefox 上通过。它在启用 Silk 的相同机器上通过。以下是我在 master 上(没有 Silk)的截图

    https://hacks.mozilla.ac.cn/wp-content/uploads/2015/02/master.jpg

    以及在 Windows 7 上启用 Silk 和 DwmComposition 的截图。

    https://hacks.mozilla.ac.cn/wp-content/uploads/2015/02/silk.jpg

    我们仍然可以改进一些,但这台机器在没有 Silk 的 Firefox 上非常卡顿,但在 Chrome/IE 上很流畅。在启用 Silk 的 Firefox 上,它非常流畅,所以我认为它确实提高了很多!

    2015 年 2 月 5 日 下午 2:09

  9. Scrambler

    Mason,这真是太棒了(非常受欢迎)的消息。感谢您的努力——它将为很多人(尤其是在游戏社区)带来巨大的改变。

    我想我对 FF 的体验完全相反。我发现很难找到一台会导致 FF 在 VSYNC 测试中失败的机器(因为我能够访问的大多数机器都是现代的,并且有一个非常快的 GPU)。但我的个人笔记本电脑始终无法通过测试(一台 2011 年的“快速”戴尔 XPS 17)。遗憾的是,我无法在上面测试 Silk,因为 FF 现在将我的显卡驱动程序列入了黑名单。

    作为额外的压力测试,您可能想尝试“双帧率压力测试”,这在 vsynctester.com/help.html 中进行了新的记录。Chrome 能够通过该测试,即使在我的 2011 年的旧笔记本电脑上也是如此。希望 FF+Silk 也可以?

    是的,希望您能找到一种方法,使当 VSYNC 间隔“触发”时,JavaScript 动画回调尽快被调用。我可以在绿线中看到这种情况有时会发生。如果这种情况始终发生,那就太好了。

    感谢您的时间和努力!我非常期待看到 Silk 发布……

    2015 年 2 月 6 日 上午 7:23

  10. anonymaus

    这将如何与具有其他固定刷新率的显示器(例如 75Hz、120Hz 或 144Hz)一起使用?

    2015 年 2 月 7 日 下午 5:36

    1. Mason

      这取决于操作系统以及操作系统报告的内容。在 Windows 上,我们使用 DwmComposition,所以我不太确定操作系统在这些情况下会报告什么。Mac 应该会生成一个 DisplayLink,它可能会正确地对齐到这些刷新率。没有针对 60 帧/秒进行硬编码,但我没有非 60Hz 显示器进行测试。

      2015 年 2 月 14 日 下午 2:28

  11. kripken

    Silk 在 Linux 上有什么时间表吗?

    2015 年 2 月 7 日 下午 10:06

    1. Mason

      不幸的是,Silk 依赖的其他一些功能我们在 Linux 上还没有,所以短期内不会支持 Linux。抱歉。

      2015 年 2 月 14 日 下午 2:29

  12. Scrambler

    Mason,有没有地方可以下载和测试 FF+Silk 的测试版(比如 Chromium 的持续构建,可以下载/提取/运行,无需安装)?

    2015 年 2 月 8 日 上午 7:53

    1. Mason

      还没有,桌面版还没有完成测试,所以可能还需要几周或几个月。

      2015 年 2 月 14 日 下午 2:29

      1. Scrambler

        我刚读到,在 nightly 版本的 about:config 中,启用 gfx.vsync.compositor、gfx.vsync.hw-vsync.enabled 和 gfx.vsync.refreshdriver 可以测试这个功能。它可以吗?

        2015 年 2 月 20 日 上午 6:13

  13. J. McNair

    所以……我一直在阅读错误报告,似乎发现了一些好消息。Chang 先生和 FX 团队的其他成员刚刚完成了 Windows 7+ 和 Mac OS X 所需的 Project Silk VSYNC 工作。但是,在启用它之前,还有大约 4 个相关错误需要修复。我本想链接错误编号,但开发人员不喜欢随机的人在错误上发表评论。

    乐观地来说,Project Silk 将在当前的 Nightly(38)或下一个 Nightly(39)中启用。然后,我们可以跟踪它,从 Aurora -> Beta -> Release。

    祝你好运,Mason!

    2015 年 2 月 16 日 下午 8:45

  14. anonymous

    因此,在 Silk 下,requestAnimationFrame (rAF) JavaScript 会在 VSYNC 对齐的情况下触发,但渲染的帧直到下一个 VSYNC 间隔才会进行合成,而在启用 Aero 的 Windows(Win8 下始终启用,Win7 下大多数时间启用)下,直到下一个 VSYNC 间隔才会到达屏幕,因为 Aero 本身就是一个合成管理器(发送到显示器的任何内容都要等到下一个间隔才能显示)——这意味着从调用 rAF 到渲染帧到达 Windows 下的屏幕,存在一个 VSYNC+VSYNC 的延迟(1/60+1/60,或 1/30 秒)?

    所以 Silk 合成在 VSYNC 对齐时总是合成前一帧吗?如果不是,请说明文章中合成何时发生(在 rAF 返回后立即发生?)

    2015 年 2 月 20 日 上午 11:25

  15. Nickolai

    Silk 项目最终会出现在 Firefox OS 中吗?如果是,我们应该期待它在什么时候出现?

    2015 年 2 月 23 日 上午 08:56

  16. Scrambler

    您指定的这种设计会导致输入延迟从一帧增加到两帧,我刚刚在 nightly 版本(Windows)中确认了这种情况。

    2015 年 2 月 23 日 上午 09:18

本文的评论已关闭。