下载文档 PDF 1.06 MB
1. 简介
Unspoken* 是一款由 Insomniac Games* 公司开发的第一人称施咒虚拟现实游戏,采用了 Oculus Touch* 控制器。 Insomniac Games 是一家经验丰富的控制台开发公司,他们的内部引擎经过扩展后可以支持虚拟现实。 从帧速率为 30 fps 的控制台体验,到高端虚拟现实设备上达到 90 fps,帧速率的大幅提升需要采用性能感知设计,以及改善引擎,以最大程度地利用系统资源。 本文介绍了如何检测系统级别的引擎瓶颈,找出其原因并且消除这些瓶颈,以提升性能。
2. 引擎架构
详细讨论之前,首先向您介绍 Insomniac Games 引擎架构, 主要由以下部分构成:
i) 主线程 (MT)
- MT 负责模拟游戏对象,以及准备下一帧的渲染工作缓冲。 前者包括发布蒙皮、物理和 vfx 工作,后者包括视锥和遮挡剔除。
ii) 渲染提交线程 (RS)
- RS 浏览渲染工作缓冲,并将其转化为渲染命令 (DirectX* 11), 包括更新各种资源,当前使用立即执行的环境,而非延迟环境。 当 RS 没有向 GPU 提交工作时,可以用作工作线程。
iii) 工作线程
- 分别有 4 个优先级较高的工作线程和 4 个优先级较低的工作线程,运行蒙皮、vfx 和物理等。
MT 的运行快一个帧,意味着它在 N+1 帧上工作;RS 将 N 帧的工作提交 GPU。 虽然导致了一帧的输入延迟,但是并行性和松散耦合有助于提升性能。
2.1 控制台对比 PC
在控制台上,GPU 几乎和 RS 同步运行。 MT 和 RS 之间保持严格的同步,当 GPU 进入后处理工作时,RS 唤醒 MT。 这使 MT 在提交蒙皮工作、更新顶点缓冲方面领先一步,有助于帧 RS 随后提交,在保持向 GPU 不间断馈送(这样做有可能产生饥饿风险)的同时,减少输入延迟。
在 PC 上,根据自变量和最大帧延迟,DirectX Present 调用发挥着遏制的作用,防止游戏 (CPU) 过度领先 GPU。 没有引起 RS 停顿的介入性 GPU 查询,便无法及时唤醒 MT,因此,引擎中的 PC 路径在 Present 返回后唤醒 MT。
3. 虚拟现实中的系统级性能分析
在 Oculus Connect* 3 发布后,我们一起看一下游戏,帧开始时,在 GPU 队列中出现了气泡(闲置时间)。 在虚拟现实中,游戏的 GPU 预算是在 10 毫秒内达到 90 fps,1 毫秒左右的 GPU 闲置时间意味着预算的 10% 未被利用! 下图中的 GPUView* 和 RAD 遥测* 时间线显示了这个问题:
之前: 帧开始时的 GPU 气泡(大约 1 毫秒)。 帧中 GTX 980* 使用 7 毫秒左右的时间渲染,包含一个游戏中的低工作负载。
之前: 基于任务的 RAD 遥测时间线视图显示了这个问题。
3.1 了解引擎独立性
气泡由 MT 和 RS 之间的几个独立性引起。
i) MT 等待 RS 在 post-Present 唤醒自己
开发虚拟现实的过程中,在 mirror-Present 前(在非 HMD 显示器上显示游戏),需要调用 Oculus* API ovr_submitFrame,后者防止(阻挡)应用提交比 HMD 更新率(在 Rift* 上达到了 90Hz)更快的帧。
在英特尔® 酷睿™ i7 6700K 上,CPU 帧像周期(RS 提交时间)约为 5 至 6 毫秒,这意味着 ovr_submitFrame 受阻了大约 5 毫秒,在这段时间内,引擎线程几乎完全闲置。
ii) RS 等待 MT 提交并同步蒙皮工作
如果 MT 不再率先运行,RS 最终会等待蒙皮定点缓冲数据的生成,然后才能提交图形缓冲区通道中的蒙皮对象。
iii) MT 等待 RS 复制面向遮挡剔除查询的下采样深度数据(每只眼睛)
引擎使用室内遮挡剔除系统,在这个系统内,MT 等待 RS 对临时缓冲进行映射、复制和取消映射,该缓冲保存每只眼睛的下采样深度数据。 使用的数据有两帧长:如果 MT 在 N 帧上工作,RS 复制 N-2 帧的深度数据后,MT 会重新投影、填补孔洞并剔除遮挡对象。
在低端的虚拟现实设备(如英特尔® 酷睿™ i5 4500 + GTX 970*)上,GPU 处理每个帧工作负载的平均时间为 9 到 10 毫秒,1 毫米的气泡使它超出了 10 毫秒的 GPU 预算,必须开始运行异步空间弯曲* (ASW),将游戏的更新速度提升至 45Hz。 总体而言,虚拟现实最终用户体验具有主观性,观察力较为敏锐的玩家在快速移动手臂或 HMD 时,能够察觉 ASW 的延迟。
3.2 消除不必要的引擎独立性
我们重构引擎,通过 RS 唤醒 MT,并调用 ovr_submitFrame 和 mirror-Present。 为 MT 提供了充足的时间来处理蒙皮和模拟工作,处理完成后,等待 RS 读回前一个帧的深度缓存(详见第 3.3 节)。 我们添加了一个开关,支持动态切换两个模式,以验证是否提升,在低端设备上运行繁重的帧工作负载时,能避免 ASW 频繁延迟。
在修复消除了独立性 (i) 和 (ii) 后,GPUView 和 RAD 遥测时间表如下所示:
之后: RS 受阻之前 MT 已经启动,减少了开始时的 GPU 气泡。
之后: 开始时的气泡减少了,深度缓冲读回的等待更为明显。
帧开始时,GPU 队列中的气泡数量有所下降,但是可以看出,遮挡读回系统(在 N 帧上工作的主线程)正在渲染线程(为 N-1 帧提交工作)上等待处理分期资源(来自 N-2 帧的深度缓冲)的 CPU 副本。 右眼的深度缓冲流程和左眼一致。
3.3 处理遮挡读回系统
左右眼睛的遮挡剔除可以共享大量的逻辑,但是我们不希望引擎为虚拟现实偏离太多。 更为重要的是,MT 算不上一个瓶颈。 游戏仍旧受 GPU 的限制,通过消除 GPU 气泡,能够满足 GPU 预算的 10 毫秒时间限制。
开始时,RS 不读回深度缓冲的原因是需要减少 GPU 饥饿的风险。 在 RS 占用 CPU 时间复制深度缓冲前,需要确保 GPU 不间断馈送,在这段时间内,不提交任何 GPU 工作。 左眼图形缓冲提交完成后,可以连续复制,无需以交错的方式复制。
进行了简单的重构后,在布满帧的区域内对最低规格设备进行测试时发现,节省了整整 1 毫秒的 GPU 时间(降低至 9–9.3 毫秒,支持 Oculus 的后期处理工作能够及时完成),还带来了 90 fps 的体验!
改变遮挡读回后: 遥测时间线显示 GPU 很少闲置。
3.4 相信您的工具
遥测 GPU 时间线(依赖于 GPU 计时器查询)显示在帧中几乎从不闲置,配有面向 Windows* DirectX 事件的事件跟踪的 GPUView 提供了更准确的时间线,显示帧开始时的小气泡。 了解各种分析和监测工具的工作原理,避免被数据误导,这点非常重要。
改变遮挡读回后: 还能继续减少部分闲置 GPU 时间。 此外,请注意各种线程上存在大量闲置时间。
此时,RS 不依靠 MT,这些气泡是由于资源更新引起的,更新需要在分配 DirectX 命令前完成。 资源更新目前通过 RS 以串行的方式进行,不使用延迟环境。 通过映射方法更新的资源需要在立即执行的环境(也就是 RS)中运行,通过 UpdateSubresource方法更新的资源可以在延迟环境中执行,节约了宝贵的驱动程序复制时间(如果 RS 被 ovr_submitFrame 阻挡时,需要在工作线程上处理)。 未来的补丁将优先考虑这个改变。
4. CPU 闲置
在虚拟现实中,由于严格的 10 毫秒 GPU 预算,针对物理、粒子更新和蒙皮等子系统创建一条 CPU 路径意义重大。 Insomniac 引擎已经利用 CPU 模拟子系统,由于 GPU 上扩展空间有限,我们探索了其他的选择,如利用高品质的预设置,通过使全部物品栩栩如生,提升浸入式体验。
Oculus 降低虚拟现实最低规格的决定非常适合采纳,但是高端设备会增加玩家的成本,而且根据最低规格定制他们的体验。 在 Unspoken 中,将预设置自动设置为基于底层系统硬件。 尽管为了增强游戏体验,开启 ASW 可能会消耗 Oculus 的运行时,但是,玩家可以自由修改质量设置,随意感受高端体验。
动态调整各种渲染参数的适应性质量系统是理想的解决方案,支持预设置质量是为玩家提供最佳体验的第一步。
超级预设置包括以下部分:
- 可破坏的对象: 赛场中有更多的对象,对玩家的咒语产生物理反应。
- 预先录制好的动画: 基于物理的破坏非常棒,但是计算成本过高, 预先录制好的动画能在利用少量运行时成本的同时,提供相似的体验。
- 粒子效果(环境和基于 curl 的湍流): 添加了基于 curl 的湍流系统,粒子可以从无政府主义者的手中发出,冬季幽灵的移动方式也更生动。
- 更高分辨率的渲染
- 临时抗锯齿处理。
- 地面上的雾和远方模型的细节。
5. 结论
过去的十年来,许多游戏引擎将物理、蒙皮、遮挡等子系统从 CPU 迁移至 GPU。帧速率为 90 fps 的虚拟现实体验生成了低于 10 毫秒的 GPU 帧预算,这个预算充满挑战。 多数游戏引擎的各种线程存在大量的 CPU 闲置时间,可以用于卸载 GPU 上的工作。 由于支持虚拟现实的设备只是 PC 生态系统中的一个子集,通过测量驱动虚拟现实游戏开发的方法有助于为玩家提供最佳的体验。
6. 扩展阅读:
- Oculus 公开的统计数据(通过 API 和 HUD)
https://developer3.oculus.com/documentation/pcsdk/latest/concepts/dg-hud/ - 异步空间弯曲 (ASW)
https://developer.oculus.com/blog/asynchronous-spacewarp/ - 通过 SDK 控制 ASW
https://developer3.oculus.com/documentation/pcsdk/latest/concepts/asynchronous-spacewarp/
如果您参加了 2017 年游戏开发者大会,可能对 3 月 3 日(周五)举办的 GDC 演讲感兴趣,该演讲以更详细的方式介绍了本文的内容。
致谢
作者特别感谢 Insomniac Games 公司的 Bob Sprentall、Yancy Young、Abdul Bezrati 和 Shaun Mccabe,以及英特尔公司的 Cristiano Ferreira、Chris Kirkpatrick、Brian Bruning 和 Dave Astle。
关于作者
Raja Bala 是英特尔公司的一名游戏开发人员关系工程师。 他喜欢和工作室合作,提升引擎和渲染性能,向开发人员普及英特尔® 显卡架构和游戏性能分析。