我们如何分析 WebXR/WebGL 应用
本文探讨了分析 WebXR 和 WebGL 应用的方法(与底层框架无关)。分析是优化应用的第一步。不进行分析的优化只是徒劳,正如我们在瓶颈部分所描述的。
注意,本文并未涉及如何解决发现的性能问题。有许多博客文章和演讲针对具体瓶颈,但一旦知道问题是什么,就会找到相关资源。
我们要分析的指标有 CPU 时间、GPU 时间、JavaScript 堆内存和应用加载时间。我们的目标是提供最全面的免费分析信息集。并且“不:多边形计数”不是我们关心的指标!
内容
瓶颈
如果没有找到应用的瓶颈,你的优化努力将不会有效。
示例
想象你在渲染一个有很多对象的大型场景。你的应用勉强达到 60 fps。你可以优化每个对象的顶点数,但帧率仍然保持在 60 fps。
CPU 负责将渲染每个对象的命令(“绘制调用”)发送到 GPU。在这种情况下,更有可能是 CPU 被分配过多的工作,使得 GPU 在等待 CPU 传送更多工作时空闲无事可做!
但是我们不知道…直到我们进行测量。这就是分析的目的。
瓶颈类型
应用程序的任何部分都可能导致瓶颈。以下是一些常见瓶颈的例子,按频率排序:
CPU 绘制调用:对驱动程序的调用过多导致开销过大。
垃圾:应用程序运行良好,但产生的垃圾导致以固定或不固定的间隔出现打嗝。
CPU 逻辑:应用程序无法足够快速地为 GPU 提供工作。通常是由于繁重的物理模拟或光线投射引起的。
GPU 片段着色:每片段性能成本过高。
GPU 顶点处理:每顶点处理需求过高。
GPU 解析:由移动 GPU 上的后期处理引起。
GPU 顶点读取:顶点内存未被快速读取。
每种瓶颈可能有其子瓶颈。
指标
我们将分析的指标包括:
CPU 时间
任何 XR 应用的工作都分为 CPU 和 GPU。CPU 负责为 GPU 准备图形工作并运行应用逻辑。
任何 JavaScript 代码都将在 CPU 上运行,以准备绘制调用、执行资源加载、模拟物理、渲染音频和计算场景图变换。
GPU 时间
GPU 负责图形的繁重工作。虽然 CPU 会发送类似“用着色器 Y 和纹理 Z 以及材质参数 W 绘制网格 X”的绘制调用,但 GPU 会执行实际的光栅化和每顶点变换以生成屏幕上的像素。
GPU 还负责将最终图像发送到屏幕,等待“V-Sync”,该功能将屏幕的刷新率与应用的刷新率同步。
帧率与 V-Sync
我们不使用帧率(每秒帧数 = fps)来分析我们的应用。
这个指标仅用于解释理解性能与 V-Sync 交互的复杂性。它过于粗略,无法进行有效的判断。
将 V-Sync 视为_固定的截止日期_:每秒 60、72、90 或更多截止日期(帧率)。我们将“达到 V-Sync”称为在截止日期前渲染并提交帧。
当你错过截止日期时,所有工作都将被丢弃,你需要尝试赶上下一个截止日期。 在灵活帧率环境中,这可能意味着你的驱动程序会将你的帧率降至一半。
如果你的应用只是稍慢一点,这意味着你会看到例如 30 fps 而不是 59 fps,讲述一个完全不同的故事。也许你的应用在 3ms 的 CPU 和 3ms 的 GPU 时间运行得相当不错,但是因为工作开始得晚,你错过了目标帧率的 V-Sync—这将有效帧率减半。 这里没有顶点计数、绘制调用或任何经典优化能帮助你。
延迟
延迟,即从输入(例如头部运动)到完成帧的时间间隔,对 VR 尤其重要。WebXR 实现通常会为我们处理这个问题,如果我们不使用我们的帧预算,可能会稍微延迟帧回调,以减少延迟。我们在 WebXR 有限的控制能力,因此不会在本文中进行讨论。
垃圾回收
JavaScript 带有内存管理,可以让你在分配时无所顾忌。因此,通常会这样做。
在不需要管控内存的情况下,你失去了指定何时希望管理内存的控制权。这个过程称为“垃圾回收”,将在应用生命周期的随机时间发生——例如,当你即将达到 V-Sync 并准备提交你的帧时。
垃圾回收可能需要 0.1 - 10 毫秒。考虑到你通常的 VR 帧预算是 11 毫秒,你_绝对_不希望这种情况在随机时间发生。
那么我们该如何避免它呢?唯一的方法是避免_任何_需要清理的垃圾。你产生的越少,垃圾回收打嗝就越小且越罕见。
应用加载时间
就像网站加载一样,用户对使用你的应用的热情随着等待时间的增加而减弱。由于 WebXR 应用相对较大,与网站相比,可能会有更多的包容度,但这并不需要。
通过提前启动应用并稍后加载不立即需要的资源,我们可以减少感知的加载时间。
通过优化资产并确保我们的服务器设置最佳,我们可以减少总体加载时间。
通过使用需要较少解析的格式,我们可以减少 CPU 在下载资源后所需的工作量。
工具
在本文中,我们将介绍以下工具:
- Chrome Profiler,分析[CPU, GPU, 垃圾]
- Chrome Networking tab,分析[加载时间]
- OVR Profiler Tool,分析[CPU, GPU]
- Spector.js 浏览器插件,分析[CPU, GPU]
- WebGL Disjoint Timer Query,分析[GPU]
- Wonderland Editor Profiler(仅限 Wonderland Engine)。分析[CPU, GPU]
Chrome Profiler
Chrome 内置分析器可以让你分析 JavaScript CPU 时间、垃圾回收和非常粗略的 GPU 帧时间。
你可以通过导航到任何网站并按 Ctrl + Shift + C
(MacOS 上为 Command + Shift + C
)找到性能选项卡。找到“Performance”。要记录一个分析会话,点击左上方的记录按钮(Ctrl/Command + E
)。通常 3-5 秒就足够,因为我们通常关注单个帧。
这在 Android 设备上的远程调试时也有效,比如 Meta Quest 或你的智能手机。
Safari 也有类似的分析器用于 Mac、iOS 设备和 Apple Vision PRO(例如,在 Apple Vision PRO 模拟器中运行的 Safari)。
Chrome 内存分析器
在垃圾回收中,我们描述了原本流畅运行的应用出现卡顿的情况。
为了找到瓶颈,浏览器提供了一种方法来采样 JavaScript 堆。这是你在上面描述的Chrome Profiler中在 Chrome 中启用它的方法:

示例
以下是在 Meta Quest 2 上的 Elysian(基于 Three.js)的分析:
你可以看到“JS Heap”在 14.1 MB 到 23.3 MB 之间波动。
每当内存突然下降时,我们会发现垃圾回收发生。在这种情况下,GC 非常大,以至于延迟了下一帧的开始,导致帧丢失:

因此,我们必须希望丢失的帧是从最后一帧重投影的,否则会发生严重的卡顿。 由于动画无法重投影,无论如何都会有一些卡顿。
网络选项卡
任何浏览器的网络选项卡都是分析应用加载时间的绝佳工具。
你可以通过导航到任何网站并按 Ctrl + Shift + C
(MacOS 上为 Command + Shift + C
)找到网络选项卡。找到“Networking”。
要记录网络活动,请在打开选项卡时重新加载页面。
阻塞下载
如果某个资源在应用启动时不需要立即使用,应延迟加载,因为浏览器将只会同时运行有限的并行请求(例如,Chrome 为 6 个)。
Meta Quest 性能 HUD
在 Meta Quest 上分析 VR 渲染时,可以使用性能 HUD。
通过 Meta Quest Developer Hub 可以最轻松地安装它。
这对调试与视图相关的性能问题特别有用,因为你可以在获得性能的连续反馈的同时使用头显。
示例
在以下示例中,Ayushman Johri 展示了他的基于 Wonderland Engine 的“Vintage Study Room”使用 Meta Quest 性能 HUD 的出色性能:
这是使用 @MetaQuestVR FPS 图表进行的性能测试!
— Ayushman Johri ✨ (@AyushmanJohri) August 19, 2023
我会提到,与不进行系统记录相比,我观察到了更多的陈旧帧~
此外,出于艺术选择,我决定为一些超详细的资产使用未压缩纹理 ✨
虽然不完美,但已经很接近了! pic.twitter.com/MLzWVLHItn
OVR GPU Profiler
如果你遇到顶点或片段着色瓶颈,你会需要更清楚地了解是什么在你的着色器中占用了最多时间。
ovrgpuprofiler 是一个非常尖锐的工具。如果你对 GPU 内存和架构有一些了解,它会提供很多见解。
通过 adb
安装到你的 Meta Quest 头盔上并通过 adb shell
运行:
(来源:developer.oculus.com)
示例输出如下所示:
(修改自:developer.oculus.com)
你经常会听到,读取和写入内存通常是着色器程序中最昂贵的操作。然而这是否正确取决于你的内存操作是否 cache 友好。
L1(“一级”)缓存内存速度极快。确保使用它,请遵循局部性原则:访问与你先前访问的内存位置相近的内存。
Spector.js
Spector.js 是适用于 Chrome 和 Firefox 的浏览器插件,允许捕获 WebGL 帧跟踪。该工具可以显示完整的命令列表并总结统计数据,如顶点数和绘制调用。
从 Chrome 插件商店 或Firefox 插件库安装它。你还可以通过 HTML 标签嵌入工具以支持不支持插件的浏览器。

首先通过顶部的插件按钮启用工具,然后点击红色的记录按钮录制帧。

你可以看到,Wonderland Engine 在总共 11 个绘制调用中绘制了许多对象。对于其他任何框架,这个数字将高出 10-100 倍。
Disjoint Timer Query
EXT_disjoint_timer_query 扩展是一个 WebGL 扩展,允许测量一组 WebGL 命令的 GPU 时间。在 Chrome 上支持得较好[2023 年 8 月],如果启用了“WebGL Debug Extensions”Chrome 标志。
由于所有命令异步在 GPU 上运行,时间测量也需要异步安排。
Wonderland Editor Profiler
Wonderland Editor 自带的分析工具可以帮助了解你的 WebXR 应用的性能可能在哪里遭受影响。
结语
每个框架都有其特定的性能特征。大多数在其他任何事物之前 都是绘制调用瓶颈,然后是片段瓶颈—如果未达到 90 fps,无需去低多面体化!
我们从头设计 Wonder- land引擎,避免了以上大多数瓶颈—每年收入高达 12 万美元 都是 免费的。 有关企业许可证和支持,请来信至[email protected]。
试用 Wonder- land引擎 现在前来节省时间优化。
