Quality Fundamentals:打磨HoloLens App性能的首选工具
理解混合现实应用性能的重要性
(映维网 2021年09月02日)如果你的应用不能以最佳帧速率运行,用户体验就会大大降低。全息影像会显得不稳定,环境的头部追踪不准确,从而导致用户体验不佳。对于混合现实开发而言,必须将性能视为第一优先功能,而不是后面的打磨优化任务。
所以,微软日前撰文介绍了理解混合现实应用性能的重要性。下面是映维网的具体整理:
我们最近发布了一个名为 “Quality Fundamentals(质量基础)”的应用程序,涵盖用于HoloLens 2应用的常见性能、设计和环境问题和解决方案。这个应用程序非常适合以下内容。
下面列出了每个目标平台的目标性能帧速率值:
平台 | 目标帧速率 |
HoloLens | 60 FPS |
Windows Mixed Reality Ultra PCs | 90 FPS |
Windows Mixed Reality PCs | 60 FPS |
下面的框架概述了实现目标帧速率的最佳实践。另外,你可以参阅Unity相关性能建议,学习在Unity环境测量和提高帧率的技巧。
1. 理解性能瓶颈
如果你应用帧率低于目标,第一步就是分析和理解计算量最多的位置。下面是负责渲染场景的两个主要处理器:CPU和GPU。它们分别处理混合现实应用的不同方面。
瓶颈可能出现在以下三个关键位置:
- 应用线程- CPU:负责应用逻辑,包括处理输入、动画、物理和其他应用逻辑。
- 渲染线程- CPU到GPU:负责将绘制调用提交到GPU。当应用想要渲染某个对象时(如多维数据集或模型),这个线程会向GPU发送请求以执行操作。
- GPU:最常见的情况是处理应用程序的图形管道,以将3D数据 (模型、纹理等) 转换为像素。它最终会生成一个要提交到设备屏幕的二维图像。
通常情况下,HoloLens应用属于GPU-Bound,但并不总是如此。你可以使用下面的工具和技术来确定应用程序的瓶颈所在。
2. 如何分析应用程序
有一系列的工具可帮助你确定混合现实应用程序的性能配置文件和潜在瓶颈。
下面是可以帮助你收集深入剖析信息的常见工具:
- Intel Graphics Performance Analyzers
- Visual Studio Graphics Debuggers
- Unity Profiler
- Unity Frame Debugger
- Unreal Insights
- PIX
- GPU Pofiling in Unreal
3. 如何在任意环境中剖析应用
确定应用是GPU-Bound还是CPU-Bound的一种方法是降低渲染目标输出的分辨率。通过减少要计算的像素数,你可以减少GPU负载。设备将渲染一个较小的纹理,然后up-sample显示最终图像。
降低呈现分辨率后,如果:
- 应用帧率增加,则可能是GPU-Bound
- 应用帧率没变,则可能是CPU-Bound
注意:Unity允许你通过XRSettings.renderViewportScale属性在运行时轻松修改应用的渲染目标分辨率。设备提供的最终图像具有固定分辨率。平台将采样较低分辨率输出,以生成更高分辨率图像。
CS
UnityEngine.XR.XRSettings.renderScale = 0.7f;
4. 如何优化你的应用程序
4.1 CPU性能建议
通常,CPU的大部分工作都涉及到执行场景“模拟”和处理应用逻辑。以下是可以进行优化的地方:
- 动画
- 物理
- 内存分配
- 复杂算法 (如逆向运动)
4.2 GPU性能建议
4.2.1 理解带宽与填充速率4.2.1
在GPU渲染帧时,应用可以分成内存带宽约束或填充速率约束。
内存带宽是GPU可从内存执行读取和写入操作的速率若要确定带宽约束,请降低纹理质量并检查帧速率是否已提高。在Unity中,通过“编辑” > “项目设置” > “质量”改变纹理质量。
填充速率是指每秒可以通过GPU绘制的像素。若要确定填充速率约束,请降低显示分辨率并检查帧速率是否已提高。在Unity中,使用XRSettings.renderViewportScale属性
内存带宽优化一般涉及以下操作:
- 更低的纹理分辨率
- 使用更少纹理 (法线、镜面等)
填充速率侧重于减少需要为最终呈现的像素计算的操作的数量,包括:
- 要渲染/处理的对象数量
- 每个着色器的操作数量
- 到最终结果的GPU阶段数量 (几何着色器、后处理效果等等数)
- 渲染像素的数量 (显示分辨率)
4.2.2 减少多边形计数
较大的多边形计数会导致更多的GPU操作,所以减少场景中的多边形数量能够减少渲染时间。存在增加着色几何成本的其他因素,但多边形计数是确定渲染场景所需工作量的最简单指标。
4.2.3 限制overdraw
当显示多个对象,但屏幕未显示过度绘制时,就会出现高overdraw。想象一下,一堵墙的后面存在对象。所有几何都将进行处理,但由于你根本看不到后面的对象,所以你只需呈现不透明的墙壁即可。
4.2.4 着色器
着色器是在GPU运行的小程序并执行以下两个重要步骤:
- 确定哪个顶点应该绘制和它们在屏幕空间的位置(顶点着色器)
- 确定每个像素的颜色 (像素着色器)
通常,着色器会执行众多转换和照明计算。尽管复杂的照明模型、阴影和其他操作可能会产生极好的结果,但它们同时成本高昂。减少着色器中计算的操作数可以极大地减少GPU每帧所需的工作量。
所以,你可以参考下面的着色器编码建议
- 尽可能使用双线性滤波
- 重新排列表达式以使用MAD intrinsics同时执行multiply和add
- 尽可能在CPU执行预计算,并将其作为常量传递给材质
- 优选将操作从像素着色器移到顶点着色器。通常,顶点的数目要小于像素数(720p是921600像素,1080p是2073600像素,依此类推)
4.2.5 删减GPU阶段
后期处理效果可能比较成本昂贵并增加应用的填充率,例如MSAA这样的抗锯齿技术。对于HoloLens,建议避免使用所述技术和其他着色器阶段,如几何、球面和计算着色器。
4. 3 内存建议
过多的内存分配和回收操作可能导致性能不一致等不利影响。在Unity中进行开发时,明确内存的注意事项尤其重要,因为内存管理由Garbage Collector控制。
4.3.1 对象池
对象池是一种降低对象连续分配和回收成本的热门技术。它是通过以下方式实现:分配一个由相同对象构成的较大池,并重复使用池中非活动的可用实例,而不是在各个时间内不断生成和销毁对象。对象池非常适合在应用中具有可变生命周期的可重用组件。