
游戏开发者的性能分析技巧
流畅的性能对于为玩家创造沉浸式游戏体验至关重要。为了确保您的游戏经过优化,一致的端到端性能分析工作流程是高效游戏开发的“必备条件”,它始于一个简单的三点程序:
- 在进行重大更改之前进行分析:建立基准。
- 在开发过程中进行分析:跟踪并确保更改不会破坏性能或预算。
- 之后进行分析:证明更改达到了预期效果。
本页面概述了游戏开发者的一般性能分析工作流程。它摘自电子书,终极Unity游戏性能分析指南, 可免费下载(Unity 6版本的指南将很快提供)。这本电子书由外部和内部的Unity游戏开发、性能分析和优化专家共同创建。
在本文中,您可以了解与性能分析相关的有用目标、常见的性能瓶颈,例如CPU受限或GPU受限,以及如何更详细地识别和调查这些情况。
设定帧预算
玩家通常使用帧率或每秒帧数(fps)来衡量性能,但作为开发者,通常建议使用帧时间(毫秒)。考虑以下简化场景:
在运行时,您的游戏在0.75秒内渲染了59帧。然而,下一帧的渲染时间为0.25秒。平均交付的帧率为60 fps听起来不错,但实际上玩家会注意到卡顿效果,因为最后一帧的渲染时间为四分之一秒。
这就是为什么每帧的时间预算很重要的原因之一。这为您在分析和优化游戏时提供了一个明确的目标,最终为您的玩家创造了更流畅和一致的体验。
每帧的时间预算将基于您的目标fps。一个目标为30 fps的应用程序每帧应始终少于33.33毫秒(1000毫秒/30 fps)。同样,目标为60 fps则每帧留有16.66毫秒(1000毫秒/60 fps)。
您可以在非交互序列中超出此预算,例如在显示UI菜单或场景加载时,但在游戏过程中不能超出。即使是单个超出目标帧预算的帧也会导致卡顿。
注意:在VR游戏中保持一致的高帧率对于避免造成玩家恶心或不适至关重要,并且通常是您的游戏获得平台持有者认证所必需的。
每秒帧数:一个具有误导性的指标
玩家衡量性能的常见方式是使用帧率或每秒帧数。然而,建议您使用毫秒的帧时间。要理解原因,请查看上面的fps与帧时间的图表。
考虑这些数字:
1000 毫秒/秒 / 900 帧每秒 = 每帧 1.111 毫秒
1000 毫秒/秒 / 450 帧每秒 = 每帧 2.222 毫秒
1000 毫秒/秒 / 60 帧每秒 = 每帧 16.666 毫秒
1000 毫秒/秒 / 56.25 帧每秒 = 每帧 17.777 毫秒
如果您的应用程序以 900 帧每秒运行,这意味着每帧的时间为 1.111 毫秒。在 450 帧每秒时,每帧为 2.222 毫秒。这代表每帧仅有 1.111 毫秒的差异,尽管帧率似乎下降了一半。
如果您查看 60 帧每秒和 56.25 帧每秒之间的差异,分别为每帧 16.666 毫秒和 17.777 毫秒。这也代表每帧多出 1.111 毫秒,但在这里,帧率的下降在百分比上感觉远不那么戏剧化。
这就是为什么开发者使用平均帧时间来基准游戏速度而不是帧每秒。
除非您低于目标帧率,否则不要担心帧每秒。专注于帧时间来衡量您的游戏运行速度,然后保持在您的帧预算内。
阅读原始文章,“罗伯特·邓洛普的帧每秒与帧时间”,以获取更多信息。

移动挑战
热控制是开发移动设备应用程序时需要优化的最重要领域之一。如果 CPU 或 GPU 由于代码效率低下而长时间全速运行,这些芯片会变热。为了避免过热和对芯片的潜在损害,操作系统将降低设备的时钟速度以使其冷却,从而导致帧卡顿和糟糕的用户体验。这种性能降低被称为热节流。
更高的帧率和增加的代码执行(或DRAM访问操作)会导致电池消耗和热量产生增加。糟糕的性能也可能使您的游戏在低端移动设备的整个部分中无法玩,这可能导致错失市场机会。
在解决热量问题时,请考虑您可以使用的预算作为系统范围的预算。
通过提前分析来优化您的游戏,以对抗热量限制和电池消耗。根据目标平台硬件调整项目设置,以应对热量和电池消耗问题。
在移动设备上调整帧预算
应对设备热量问题的一个一般建议是在长时间游戏中留出大约35%的帧空闲时间。这给移动芯片提供了冷却的时间,并有助于防止过度的电池消耗。使用每帧33.33毫秒的目标帧时间(对于30 fps),移动设备的帧预算将大约为每帧22毫秒。
计算如下:(1000 ms / 30) * 0.65 = 21.66 ms
要在移动设备上实现60 fps,使用相同的计算需要目标帧时间为(1000毫秒/60)* 0.65 = 10.83毫秒。在许多移动设备上实现这一点是困难的,并且会使电池消耗速度是目标30 fps的两倍。出于这些原因,许多移动游戏的目标是30 fps而不是60。使用Application.targetFrameRate来控制此设置,并参考"设置帧预算"部分在分析电子书中以获取有关帧时间的更多详细信息。
移动芯片上的频率缩放可能使在分析时识别帧空闲时间预算分配变得棘手。您的改进和优化可能会产生净积极效果,但移动设备可能会降低频率,因此运行更凉爽。使用自定义工具,如FTrace或Perfetto来监控移动芯片频率、空闲时间和缩放,在优化之前和之后。
只要您保持在目标fps的总帧时间预算内(例如30 fps的33.33毫秒),并看到您的设备工作更少或记录较低的温度以维持此帧率,那么您就走在正确的轨道上。
在移动设备上增加帧预算的另一个原因是考虑到现实世界的温度波动。在炎热的日子里,移动设备会过热并难以散热,这可能导致热降频和糟糕的游戏性能。预留一部分帧预算以帮助避免这种情况。

减少内存访问操作
在移动设备上,DRAM访问通常是一个耗电的操作。Arm的针对移动设备图形内容的优化建议表示,LPDDR4内存访问的成本大约为每字节100皮焦耳。
通过以下方式减少每帧的内存访问操作数量:
- 降低帧率
- 在可能的情况下降低显示分辨率
- 使用简化的网格,减少顶点数量和属性精度
- 使用纹理压缩和mipmap
当您需要关注利用Arm CPU或GPU硬件的设备时,Arm Performance Studio工具(特别是Streamline Performance Analyzer)包括一些很好的性能计数器,用于识别内存带宽问题。可用的计数器在相应的用户指南中列出并解释,例如,Mali-G710性能计数器参考指南。请注意,Arm Performance Studio GPU分析需要Arm Immortalis或Mali GPU。
为基准测试建立硬件层级
除了使用特定平台的分析工具外,为每个平台和您希望支持的质量层级建立层级或最低规格设备,然后对这些规格进行性能分析和优化。
例如,如果您针对移动平台,您可能决定支持三个层级,并根据目标硬件切换功能的质量控制。然后,您针对每个层级中的最低设备规格进行优化。另一个例子是,如果您正在为控制台开发游戏,请确保在旧版本和新版本上进行分析。
我们的最新移动优化指南提供了许多技巧和窍门,帮助您减少热降频并延长运行您游戏的移动设备的电池寿命。

从高到低级别的性能分析
在分析时,您希望确保将时间和精力集中在可以产生最大影响的领域。因此,建议在分析时采用自上而下的方法,这意味着您从渲染、脚本、物理和垃圾回收(GC)分配等类别的高层次概述开始。一旦您确定了关注领域,就可以深入了解更详细的信息。利用这个高层次的过程收集数据,并记录最关键的性能问题,包括导致不必要的托管分配或核心游戏循环中过度 CPU 使用的场景。
您需要首先收集 GC.Alloc 标记的调用栈。如果您对这个过程不熟悉,可以在电子书中找到标题为“定位应用程序生命周期中的重复内存分配”的部分中的一些提示和技巧。
如果报告的调用栈不够详细,无法追踪分配或其他减速的来源,您可以执行第二次分析会话,并启用深度分析,以找到分配的来源。我们在电子书中更详细地介绍了深度分析,但总的来说,它是分析器中的一种模式,捕获每个函数调用的详细性能数据,提供对执行时间和行为的细致洞察,但与标准分析相比,开销显著更高。
在收集帧时间“罪犯”的笔记时,请务必注意它们与帧的其余部分的相对比较。当启用深度分析时,这种相对影响可能会被扭曲,因为深度分析通过对每个方法调用进行插桩,增加了显著的开销。
尽早分析
虽然您应该始终在项目的整个开发周期中进行分析,但在早期阶段进行分析所获得的收益是最显著的。
尽早并经常进行分析,以便您和您的团队理解并记住项目的“性能特征”,以便进行基准测试。如果性能急剧下降,您将能够轻松发现问题并解决它。
虽然在编辑器中进行分析为您提供了一种轻松识别主要问题的方法,但最准确的分析结果总是来自于在目标设备上运行和分析构建,同时利用特定平台的工具深入挖掘每个平台的硬件特性。这种组合将为您提供跨所有目标设备的应用程序性能的整体视图。例如,您可能在某些移动设备上受限于 GPU,而在其他设备上受限于 CPU,您只能通过在这些设备上进行测量来了解这一点。
识别性能问题
下载此图表的可打印 PDF 版本 在这里。
分析的目的是识别瓶颈作为优化的目标。如果您依赖猜测,可能会最终优化游戏中不是瓶颈的部分,从而导致整体性能几乎没有改善。一些“优化”甚至可能会恶化您游戏的整体性能,而其他一些可能需要大量劳动但结果微不足道。关键是优化您集中时间投资的影响。
上面的流程图说明了初始分析过程,后面的部分提供了每个步骤的详细信息。它们还展示了来自真实Unity项目的分析捕获,以说明需要关注的内容。
要全面了解所有CPU活动,包括何时等待GPU,请在分析器的CPU模块中使用时间线视图。熟悉常见分析器标记以正确解读捕获。某些分析器标记可能会根据您的目标平台而有所不同,因此请花时间探索您游戏在每个目标平台上的捕获,以了解您项目的“正常”捕获是什么样的。
项目的性能受限于耗时最长的芯片和/或线程。这就是优化工作应集中关注的领域。例如,想象一下一个目标帧时间预算为33.33毫秒且启用了垂直同步的游戏的以下场景:
- 如果CPU帧时间(不包括垂直同步)为25毫秒,GPU时间为20毫秒,那没问题!您受限于CPU,但一切都在预算之内,优化不会提高帧率(除非您将CPU和GPU都降到16.66毫秒以下,并提升到60 fps)。
- 如果CPU帧时间为40毫秒,GPU为20毫秒,您受限于CPU,需要优化CPU性能。优化GPU性能无济于事;实际上,您可能希望将一些CPU工作转移到GPU上,例如,在适用的情况下使用计算着色器而不是C#代码,以平衡工作负载。
- 如果CPU帧时间为20毫秒,GPU为40毫秒,您受限于GPU,需要优化GPU工作。
- 如果CPU和GPU都为40毫秒,您受限于两者,需要将两者都优化到33.33毫秒以下,以达到30 fps。
请查看这些资源,进一步探讨CPU或GPU受限的情况:

您保持在帧预算之内吗?
在开发过程中,早期和频繁地对项目进行分析和优化将帮助您确保所有应用程序的 CPU 线程和整体 GPU 帧时间都在帧预算内。指导此过程的问题是,您是否在帧预算内?
上面是一个来自 Unity 移动游戏的性能捕获图像,该游戏由一个持续进行性能分析和优化的团队开发。该游戏在高规格手机上目标为 60 fps,在中低规格手机上目标为 30 fps,例如此捕获中的手机。
请注意,所选帧的几乎一半时间被黄色 WaitForTargetFPS Profiler 标记占用。应用程序已将 Application.targetFrameRate 设置为 30 fps,并且 VSync 已启用。主线程上的实际处理工作在大约 19 ms 时标完成,其余时间用于等待剩余的 33.33 ms 过去,然后开始下一帧。尽管此时间用 Profiler 标记表示,但主 CPU 线程在此期间基本上处于空闲状态,允许 CPU 冷却并使用最少的电池电量。
在其他平台上或禁用 VSync 时,需注意的标记可能会有所不同。重要的是检查主线程是否在您的帧预算内运行,或者是否正好在您的帧预算上,并有某种标记指示应用程序正在等待 VSync,以及其他线程是否有任何空闲时间。
空闲时间由灰色或黄色 Profiler 标记表示。上面的截图显示渲染线程在 Gfx.WaitForGfxCommandsFromMainThread 中空闲,这表示它在一帧中完成了向 GPU 发送绘制调用,并在等待 CPU 在下一帧中发送更多绘制调用请求。同样,尽管 Job Worker 0 线程在 Canvas.GeometryJob 中花费了一些时间,但大部分时间它是空闲的。这些都是应用程序舒适地在帧预算内的迹象。
如果您的游戏在帧预算内
如果您在帧预算内,包括为电池使用和热限制而对预算所做的任何调整,您就完成了关键的性能分析任务。您可以通过运行 Memory Profiler 来得出结论,以确保应用程序也在其内存预算内。
上面的图像显示游戏在 30 fps 所需的约 22 ms 帧预算内轻松运行。请注意 WaitForTargetfps 填充主线程时间直到 VSync,以及渲染线程和工作线程中的灰色空闲时间。还请注意,可以通过查看 Gfx.Present 帧逐帧的结束时间来观察 VBlank 间隔,并且您可以在时间轴区域或顶部的时间标尺上绘制时间尺度,以测量从一个到下一个的时间。

CPU受限
如果您的游戏不在 CPU 帧预算内,下一步是调查 CPU 的哪个部分是瓶颈——换句话说,哪个线程最忙。
整个 CPU 工作负载成为瓶颈的情况很少见。现代 CPU 具有多个不同的核心,能够独立且同时执行工作。不同的线程可以在每个 CPU 核心上运行。完整的 Unity 应用程序使用一系列线程用于不同的目的,但最常见的用于查找性能问题的线程是:
- 主线程:默认情况下,大多数游戏逻辑/脚本在这里执行其工作。大多数 Unity 系统,例如物理、动画、UI 和渲染的初始阶段,都在这里执行。
- 渲染线程:这处理准备工作(例如,场景中哪些对象对相机可见,哪些因超出视锥体、被遮挡或因其他标准被剔除而不可见),这些工作必须在向 GPU 发送渲染指令之前完成。
- 在渲染过程中,主线程检查场景并执行相机剔除、深度排序和绘制调用批处理,从而生成要渲染的内容列表。该列表传递给渲染线程,渲染线程将其从 Unity 的内部平台无关表示转换为特定图形 API 调用,以指示特定平台上的 GPU。
- 作业工作线程:开发人员可以利用 作业系统 来调度某些类型的工作在工作线程上运行,从而减少主线程的工作负载。Unity 的一些系统和功能也利用作业系统,例如物理、动画和渲染。
主线程优化的真实世界示例
下图显示了在主线程受限的项目中可能的情况。该项目在 Meta Quest 2 上运行,通常目标帧预算为 13.88 ms (72 fps) 或甚至 8.33 ms (120 fps),因为高帧率对于避免 VR 设备中的运动病很重要。然而,即使这款游戏的目标是30帧每秒,很明显这个项目遇到了麻烦。
尽管渲染线程和工作线程看起来与在帧预算内的示例相似,但主线程在整个帧期间显然忙于工作。即使考虑到帧结束时小量的分析器开销,主线程仍然忙于超过45毫秒,这意味着这个项目的帧率低于22帧每秒。没有标记显示主线程在等待垂直同步;它在整个帧期间都很忙。
下一阶段的调查是识别帧中耗时最长的部分,并理解原因。在这个帧中,PostLateUpdate.FinishFrameRendering耗时16.23毫秒,超过了整个帧预算。更仔细的检查显示有五个名为Inl_RenderCameraStack的标记实例,表明有五个相机处于活动状态并渲染场景。由于Unity中的每个相机都会调用整个渲染管线,包括剔除、排序和批处理,因此这个项目的最高优先级任务是减少活动相机的数量,理想情况下只保留一个。
BehaviourUpdate,包含所有MonoBehaviour.Update()方法执行的分析器标记,在这个帧中耗时7.27毫秒。
在时间线视图中,品红色部分表示脚本分配托管堆内存的点。切换到Hierarchy视图,并在搜索栏中输入GC.Alloc进行过滤,显示在这个帧中分配这块内存大约耗时0.33毫秒。然而,这并不是内存分配对CPU性能影响的准确测量。
GC.Alloc标记并不是通过记录开始和结束点来计时的,像典型的分析器样本那样。为了最小化它们的开销,Unity仅记录分配的时间戳和分配的大小。
分析器为GC.Alloc标记分配一个小的、人工的样本持续时间,仅仅是为了确保它们在分析器视图中可见。实际的分配可能需要更长时间,特别是如果需要从系统请求新的内存范围。为了更清楚地看到影响,在执行分配的代码周围放置分析器标记;在深度分析中,时间线视图中品红色GC.Alloc样本之间的间隙提供了一些指示,表明它们可能花费了多长时间。
此外,分配新内存可能对性能产生负面影响,这些影响更难以测量并直接归因于它们:
- 从系统请求新内存可能会影响移动设备的功率预算,这可能导致系统减慢CPU或GPU的速度。
- 新内存可能需要加载到CPU的L1缓存中,从而推送现有的缓存行。
- 增量或同步垃圾收集可能会直接或延迟触发,因为托管内存中现有的空闲空间最终会被超出。
在帧开始时,四个 Physics.FixedUpdate 实例加起来为 4.57 毫秒。稍后,LateBehaviourUpdate(对 MonoBehaviour.LateUpdate() 的调用)耗时 4 毫秒,而 Animators 大约占 1 毫秒。为了确保该项目达到预期的帧预算和权重,所有这些主线程问题都需要调查以寻找合适的优化。
主线程瓶颈的常见陷阱
通过优化耗时最长的事情,可以获得最大的性能提升。以下领域通常是寻找主线程绑定项目优化的丰硕之地:
- 物理计算
- MonoBehaviour 脚本更新
- 垃圾分配和/或收集
- 在主线程上进行相机剔除和渲染
- 低效的绘制调用批处理
- UI 更新、布局和重建
- 动画
阅读我们的优化指南,提供了一长串可操作的优化常见陷阱的提示:
根据您想要调查的问题,其他工具也可能有帮助:
- 对于耗时较长但未能准确显示原因的 MonoBehaviour 脚本,向代码中添加 Profiler Markers 或尝试 深度分析 以查看完整的调用堆栈。
- 对于分配托管内存的脚本,启用 分配调用堆栈 以准确查看分配来源。或者,启用深度分析或使用 项目审计器,该工具显示按内存过滤的代码问题,以便您可以识别所有导致托管分配的代码行。
- 使用 帧调试器 调查绘制调用批处理不佳的原因。
有关优化游戏的全面提示,请免费下载这些 Unity 专家指南:

CPU受限:渲染线程
这是一个受其渲染线程限制的实际项目。这是一个具有等轴测视角的控制台游戏,目标帧预算为 33.33 毫秒。
Profiler 捕获显示,在当前帧的渲染开始之前,主线程等待渲染线程,如 Gfx.WaitForPresentOnGfxThread 标记所示。渲染线程仍在提交来自上一帧的绘制调用命令,并且尚未准备好接受来自主线程的新绘制调用;它还花费时间在 Camera.Render 中。
您可以区分与当前帧相关的标记和来自其他帧的标记,因为后者看起来更暗。您还可以看到,一旦主线程能够继续并开始发出绘制调用供渲染线程处理,渲染线程需要超过 100 毫秒来处理当前帧,这在下一帧期间也会造成瓶颈。
进一步调查显示,这个游戏有一个复杂的渲染设置,涉及九个不同的相机和许多由于替换着色器而导致的额外通道。该游戏还使用前向渲染路径渲染超过 130 个点光源,这可能为每个光源增加多个额外的透明绘制调用。总的来说,这些问题结合在一起导致每帧超过 3000 个绘制调用。
渲染线程瓶颈的常见陷阱
以下是需要调查的常见原因,适用于受渲染线程限制的项目:
- 绘制调用批处理不佳:这特别适用于较旧的图形 API,如 OpenGL 或 DirectX 11。
- 相机数量过多:除非您正在制作分屏多人游戏,否则您应该只拥有一个活动相机。
- 剔除不佳:这导致绘制的物体过多。调查您的相机视锥体尺寸和剔除层掩码。
渲染分析器模块显示每帧绘制调用批次和SetPass调用的概述。调查您的渲染线程向GPU发出的绘制调用批次的最佳工具是帧调试器。
解决识别出的瓶颈的工具
虽然本电子书的重点是识别性能问题,但我们之前强调的两个互补性能优化指南提供了关于如何解决瓶颈的建议,具体取决于您的目标平台是PC或控制台还是移动设备。在渲染线程瓶颈的背景下,值得强调的是,Unity根据您识别出的问题提供不同的批处理系统和选项。以下是一些选项的快速概述,我们在电子书中进行了更详细的解释:
- SRP批处理通过在GPU内存中持久存储材质数据来减少CPU开销。虽然它并不减少实际的绘制调用数量,但使每个绘制调用的成本更低。
- GPU实例化将使用相同材质的相同网格的多个实例组合成一个绘制调用。
- 静态批处理将共享相同材质的静态(非移动)网格组合在一起,因此在处理具有许多静态元素的关卡设计时可以获得优势。
- GPU驻留绘制器通过将相似的GameObjects分组,自动使用GPU实例化来减少CPU开销和绘制调用。
- 动态批处理在运行时组合小网格,这在高绘制调用成本的旧移动设备上可能是一个优势。然而,缺点是顶点变换也可能是资源密集型的。
- GPU遮挡剔除使用计算着色器通过比较当前帧和前一帧的深度缓冲区来确定对象的可见性,从而减少不必要的遮挡对象渲染,而无需预先烘焙数据。
此外,在CPU方面,可以使用Camera.layerCullDistances等技术通过根据对象与相机的距离剔除对象来减少发送到渲染线程的对象数量,从而帮助缓解相机剔除期间的CPU瓶颈。
这些只是可用选项的一部分。每个选项都有不同的优缺点。有些仅限于某些平台。项目通常需要结合使用这些系统的几种组合,并且需要了解如何充分利用它们。

CPU受限:工作线程
与主线程或渲染线程无关的 CPU 线程绑定的项目并不常见。然而,如果您的项目使用 数据导向技术栈 (DOTS),尤其是如果工作被移出主线程到使用 作业系统 的工作线程中,这种情况可能会出现。
上面的图像是编辑器中播放模式的捕获,显示了一个在 CPU 上运行粒子流体模拟的 DOTS 项目。
乍一看,这似乎是一个成功。工作线程紧密打包了 Burst 编译 的作业,表明大量工作已被移出主线程。通常,这是一个明智的决定。
然而,在这种情况下,主线程的 48.14 毫秒的帧时间和 35.57 毫秒的灰色 WaitForJobGroupID 标记,表明一切并不顺利。WaitForJobGroupID 表示主线程已安排作业在工作线程上异步运行,但它需要在工作线程完成运行之前获得这些作业的结果。WaitForJobGroupID 下方的蓝色分析器标记显示主线程在等待时运行作业,以确保作业尽快完成。
尽管作业是 Burst 编译的,但它们仍在做大量工作。也许这个项目用于快速找到彼此接近的粒子的空间查询结构应该被优化或替换为更高效的结构。或者,空间查询作业可以安排在帧的末尾,而不是开始时,结果在下一帧开始时不需要。也许这个项目试图模拟太多粒子。需要进一步分析作业的代码以找到解决方案,因此添加更细粒度的分析器标记可以帮助识别它们最慢的部分。
您项目中的作业可能没有像这个例子中那样并行化。也许您只有一个长作业在单个工作线程中运行。只要作业被安排的时间和它需要完成的时间之间的间隔足够长以便作业运行,这样是可以的。如果不是,您将看到主线程停滞,因为它在等待作业完成,如上面的屏幕截图所示。
工作线程瓶颈的常见陷阱
同步点和工作线程瓶颈的常见原因包括:
- 作业未被 Burst 编译器编译
- 在单个工作线程上运行的长时间作业,而不是在多个工作线程之间并行化
- 在作业调度的帧点与主线程需要结果的点之间的时间不足
- 帧中的多个“同步点”,要求所有作业立即完成
您可以在 CPU 使用分析器模块的时间轴视图中使用 流事件 功能来调查作业何时被调度以及主线程何时期望其结果。
有关编写高效 DOTS 代码的更多信息,请参阅 DOTS 最佳实践 指南。

GPU绑定
如果主线程在 Profiler 标记中花费大量时间,如 Gfx.WaitForPresentOnGfxThread,并且您的渲染线程同时显示标记,如 Gfx.PresentFrame 或 .WaitForLastPresent.,则您的应用程序是 GPU 绑定的。
获取 GPU 帧时间的最佳方法是使用特定于目标平台的 GPU 分析工具,但并非所有设备都能轻松捕获可靠数据。
在这些情况下,FrameTimingManager API 可以提供帮助,提供 CPU 和 GPU 上低开销的高层帧时间。
上述捕获是在使用 Vulkan 图形 API 的 Android 手机上进行的。尽管在此示例中,Gfx.PresentFrame 中花费的一些时间可能与等待 VSync 相关,但此 Profiler 标记的极长时间表明大部分时间用于等待 GPU 完成渲染前一帧。
在此游戏中,某些游戏事件触发了使用着色器的情况,该着色器使 GPU 渲染的绘制调用数量增加了三倍。在分析 GPU 性能时需要调查的常见问题包括:
- 昂贵的全屏后处理效果,如环境光遮蔽和辉光
- 由于以下原因导致的昂贵片段着色器:
- 着色器代码中的分支逻辑
- 使用全浮点精度而不是半精度,尤其是在移动设备上
- 过度使用寄存器,影响 GPU 的波前占用率
- 透明渲染队列中的过度绘制,原因是:
- 低效的用户界面渲染
- 重叠或过度使用粒子系统
- 后期处理效果
- 过高的屏幕分辨率,例如:
- 4K 显示器
- 移动设备上的视网膜显示器
- 由以下原因造成的微三角形:
- 密集的网格几何
- 缺乏细节层次(LOD)系统,这在移动 GPU 上是一个特别的问题,但也会影响 PC 和控制台 GPU
- 由于以下原因造成的缓存未命中和浪费的 GPU 内存带宽:
- 未压缩的纹理
- 没有 mipmaps 的高分辨率纹理
- 几何或细分着色器,如果启用动态阴影,可能每帧运行多次
如果您的应用程序似乎受限于 GPU,您可以使用帧调试器快速了解发送到 GPU 的绘制调用批次。然而,这个工具无法提供任何具体的 GPU 时间信息,只能展示整体场景的构建方式。
调查 GPU 瓶颈原因的最佳方法是检查来自合适 GPU 分析器的 GPU 捕获。您使用的工具取决于目标硬件和所选的图形 API。有关更多信息,请参见 电子书 中的分析和调试工具部分。


在Unity最佳实践中心中找到更多最佳实践和技巧。从超过30个指南中选择,这些指南由行业专家、Unity工程师和技术艺术家创建,将帮助您高效地使用Unity的工具和系统进行开发。