从家用游戏机到PC虚拟现实游戏: 《不语者》给我们的启示

下载文档 PDF 1.06 MB

1. 简介

《不语者》(Unspoken* ) * 是一款由 Insomniac Games* 公司开发的第一人称魔咒虚拟现实游戏,采用了 Oculus Touch* 控制器。。 Insomniac Games 是一家经验丰富的家用游戏机开发公司,他们的内部引擎经过扩展后可以支持虚拟现实技术开发。 从帧速率为 30 fps 的家用游戏机,到高端虚拟现实设备上的 90 fps,帧速率的大幅提升要求更好的性能感知设计和引擎性能改善,以实现最大程度地利用系统资源。 本文介绍了如何检测系统级别的引擎中所存在的技术瓶颈,其背后的原因,以及如何消除这些瓶颈以提升性能。

2. 引擎架构

在详细讨论之前,我们首先来介绍一下 Insomniac Games 引擎架构, 该引擎主要由以下部分构成:

i) 主线程 (MT)
- MT 负责对游戏中的物体进行模拟,以及准备下一帧的渲染工作缓冲。 前者包括蒙皮、物理和视觉效果,后者包括视锥和遮挡剔除。

ii) 渲染提交线程 (RS)
- RS 负责处理渲染工作缓冲,并将其转化为渲染命令 (DirectX* 11)。 它可以更新各种资源,并使用即时语境(immediate context),而非延迟语境(deferred context)。 当 RS 没有向 GPU 提交工作时,可以用作工作线程。

iii) 工作线程
- 我们使用 4 个高优先级工作线程和 4 个低优先级工作线程,可以运行蒙皮、物理和视觉效果等。

MT 提前运行一个帧,也就是说,当它在处理 N+1 帧时,RS 将 N 帧的工作提交至 GPU。 虽然这会导致一帧的输入延迟,但是系统本身的并行性和松散耦合特性有助于提升性能。

2.1 家用游戏机与 PC

在家用游戏机上,GPU 几乎与 RS 同步运行。 MT 和 RS 之间保持紧密同步,当 GPU 开始执行后处理工作时,RS 立即唤醒 MT。 这有助于 MT 率先提交蒙皮工作,进而更新顶点缓冲区,以确保帧 RS 随后提交。而且,GPU 能够持续提供处理资源(有可能出现资源不足的风险),同时有效降低输入延迟。

在 PC 上,DirectX Present 发挥着遏制的作用(取决于具体的参数和最大帧延迟),可防止 CPU 过度领先 GPU 现象的发生。 在没有介入性 GPU 查询(用于停止 RS)的情况下,便无法及时唤醒 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)
在 mirror-Present (在非 HMD 显示器上显示游戏)调用 Oculus* API ovr_submitFrame之前,MT 等待 RS 唤醒虚拟现实中的 post-Present。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 预算,此时必须开始运行异步空间扭曲* (Asynchronous Space Warp,ASW),将游戏速度提升至 45Hz。 总体而言,最终用户对于虚拟现实的体验具有一定的主观性。对于观察力较为敏锐的玩家来说,当他们在快速移动手臂或 HMD 时,能够察觉 ASW 的延迟。

3.2 消除不必要的引擎依赖性

我们对引擎进行重构,确保 RS 能够唤醒 MT,并调用 ovr_submitFrame 和 mirror-Present。 这有助于为 MT 提供充足的时间来处理蒙皮和模拟工作,之后,它会等待 RS 重新读取前一个帧的深度缓存(详见第 3.3 节)。 我们添加了一个开关,支持在两个模式之间动态切换,以验证是否得到改进。在低端设备上运行繁重的帧工作负载时,此举能有效避免 ASW 出现频繁延迟的现象。

下图为消除了依赖性 (i) 和 (ii) 后的 GPUView 和 RAD 遥测时间表:


之后: MT 在 RS 受阻之前已经启动,减少了开始时的 GPU 气泡。


之后: 开始时的气泡减少了,等待重新读取深度缓冲的时间更为明显。

帧开始时,GPU 队列中的气泡有所减少,但是可以看出,遮挡回读系统(在 N 帧上工作的主线程)正在渲染线程(向 N-1 帧提交工作)上等待处理分期(staging)资源(来自 N-2 帧的深度缓冲)的 CPU 副本。 右眼的深度缓冲流程和左眼一致。

3.3 处理遮挡回读系统

虽然左右眼睛的遮挡剔除在很多地方都是相同的,但是我们不希望引擎过多地偏离虚拟现实。 更为重要的是,MT 根本算不上一个瓶颈。 游戏仍旧受 GPU 的限制,消除 GPU 气泡有助于满足 10 毫秒的帧预算限制。

RS 之所以一开始不重新读取深度缓冲数据,是为了降低 GPU 资源不足的风险。 在 RS 占用 CPU 时间复制深度缓冲前,需要确保 GPU 资源充足。在这段时间内,系统不会提交任何 GPU 工作。 左眼图形缓冲提交完成后,可以连续复制,无需以交错的方式复制。

进行了简单的重构后,我们在丢弃大量帧的区域内对最低规格设备进行了测试,结果显示,GPU 时间节省了整整 1 毫秒(降低至 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 降低虚拟现实最低规格的做法对于推动普及具有积极的促进作用,对于拥有高端设备并具备一定经验的玩家,他们在根据最低规格定制自己的设备时会增加一定的成本。 在《不语者》中,系统将根据底层系统硬件自动进行预设置。 但是,玩家可以自由修改设置,体验高画质带来的效果,但这可能会影响 Oculus 的运行时,并且需要开启 ASW 才能实现。

现阶段,我们需要的理想解决方案是能够动态调整各种渲染参数的适应性质量系统,提供质量预设置功能是确保玩家获得最佳体验的前提条件。

超级预设置包括以下部分:

  1. 可破坏的对象: 赛场中有更多的对象,对玩家的魔咒产生物理反应。
  2. 预先录制好的动画: 基于物理的破坏非常棒,但是计算成本过高, 预先录制好的动画可提供相似的体验,但运行时成本大幅降低。
  3. 粒子效果(环境和基于 curl 的湍流): 添加了基于 curl 的湍流系统,粒子可以从无序大师的手中发出,冬季幽灵的移动方式也更生动。
  4. 更高分辨率的渲染
  5. 临时抗锯齿处理。
  6. 地面上的雾和远方模型的细节。

5. 结论

在过去的十年中,许多游戏引擎将物理、蒙皮、遮挡等子系统从 CPU 迁移至 GPU。要实现 90 fps 的虚拟现实体验,GPU 帧预算必须在 10 毫秒以下,这是一个非常严峻的挑战。 对于大多数游戏引擎来说,各种线程上存在大量的 CPU 闲置时间,可以用于卸载 GPU 上的工作。 由于支持虚拟现实的设备只是整个 PC 生态系统中的一小部分,游戏开发商可以采用测量驱动(measurement driven )的方法来开发虚拟现实游戏,以便为玩家提供最佳的体验。

6. 扩展阅读:

  1. Oculus 公开的统计数据(通过 API 和 HUD)
    https://developer3.oculus.com/documentation/pcsdk/latest/concepts/dg-hud/
  2. 异步空间扭曲(ASW)
    https://developer.oculus.com/blog/asynchronous-spacewarp/
  3. 通过 SDK 控制 ASW
    https://developer3.oculus.com/documentation/pcsdk/latest/concepts/asynchronous-spacewarp/

如果您参加了 2017 年游戏开发者大会,可能会对 3 月 3 日(周五)举办的 GDC 演讲感兴趣,该演讲更加详细地介绍了本文的内容。或者您可以观看以下视频,为您带来《不语者》在GDC现场的精彩花絮。

致谢

作者特别感谢 Insomniac Games 公司的 Bob Sprentall、Yancy Young、Abdul Bezrati 和 Shaun Mccabe,以及英特尔公司的 Cristiano Ferreira、Chris Kirkpatrick、Brian Bruning 和 Dave Astle。

关于作者

Raja Bala 是英特尔公司的一名游戏开发人员关系工程师。 他喜欢和工作室合作,提升引擎和渲染性能,向开发人员普及英特尔® 显卡架构和游戏性能分析方面的知识。

有关编译器优化的更完整信息,请参阅优化通知