前言
如果你的项目团队不大,没有时间精力去做 "跑测→收集.rec.upipelinecache→再打包"这一套(Bundled PSO Cache),那么 PSO Precache 是一个开箱即用的UE4/5自带的功能。
Precache的"Pre"体现在哪
起初我听到有的游戏"按需"地去缓存PSO,我就不理解precache这种方法哪里有体现"预测",似乎就是即刻按需编译PSO。这是一个误解。
那么所谓的"预测"(Pre)是什么意思呢?主要体现在将原本在游戏运行时(in-game / runtime中的玩家游玩时刻)进行的耗时操作,提前到资源加载阶段完成(in-game / runtime 中的loading时刻),从而避免在实时渲染帧中因编译管线状态对象(PSO)而导致的卡顿(Hitch)。如下图所示,注意下图都是 runtime中,且区分了"绘制时"与"加载时"。

"预先"的具体体现是在:
-
时机前置:在绘制发生之前
如时序图所示,传统的即时编译模式下,PSO的创建和编译是在渲染线程发出具体绘制指令(DrawCall)的瞬间才触发的,这会导致渲染线程必须等待编译完成,造成帧率下降。而PSO预缓存机制将这项工作转移到了资源加载阶段(例如关卡加载界面或对象流送时)。系统在加载网格体、材质等资源时,就会自动分析并触发其可能需要的PSO的编译任务,远早于这些资源被实际渲染到屏幕上的时刻。
-
预测性准备:分析而非响应
"预先"还体现在系统的预测行为 上。当一个静态网格体组件被加载时,其
PostLoad函数会被调用。在这个过程中,预缓存系统会分析该网格体的顶点工厂信息、其上附着的材质在所有画质等级下可能产生的着色器变体,以及它可能参与的所有渲染通道(如深度预填充、主渲染、阴影生成等)。系统会基于这些信息,计算出一个需要为该网格体预编译的PSO列表,而不是等到相机看到它时才去准备。 -
异步编译:不阻塞主线程
这个预测和编译过程是在后台异步 完成的。这意味着,即使在加载界面需要编译成千上万个PSO,也不会阻塞游戏主线程的运行。玩家可能感受到的是加载时间变长,但进入游戏后,由于大部分PSO已经准备就绪,游戏过程的流畅度会得到极大保障。这实现了将不可预测的运行时卡顿 转换为可预测的加载时间等待的优化目标。
总而言之,PSO预缓存中的"预先",其精妙之处在于主动规划、提前准备。它将一个高延迟的、破坏性的操作从关键的实时渲染路径中移除,通过利用加载阶段相对"空闲"的时间来预先支付渲染成本,从而为玩家提供稳定流畅的帧率体验。这是一种典型的用空间(内存、加载时间)换取时间(运行时性能)的优化策略。
理解UE4中"开箱即用"的PSO Precache默认策略非常重要,它能帮助您建立优化的基础。简单来说,如果您不进行任何自定义配置,UE4的PSO Precache会尝试以一种**"尽力而为"的自动化模式** 工作,其核心目标是在资源加载阶段,预测并提前编译游戏可能需要的PSO,从而避免这些编译操作在游戏运行时(渲染帧中)发生,导致卡顿。
下面这个表格详细梳理了PSO Precache的默认工作策略。
| 核心方面 | "开箱即用"的默认策略 |
|---|---|
| 触发时机 | 在网格体组件(如UStaticMeshComponent, USkeletalMeshComponent)被加载、调用其PostLoad()函数时自动触发。 |
| 预测逻辑 | 系统会分析该网格体所关联的材质 和其顶点工厂 ,并结合当前的画质等级等全局渲染状态,计算出一系列可能用于渲染该网格体的PSO组合。 |
| 工作方式 | 预测出的PSO编译任务会被提交到后台异步线程执行,以避免阻塞主线程和渲染线程。 |
| 缓存机制 | 编译好的PSO会缓存在内存中。同时,现代图形API的驱动程序也会在磁盘上维护一个缓存,游戏第二次运行时加载速度会大大加快。 |
| 核心目标 | 将PSO编译的耗时操作从实时的游戏渲染帧 中转移至资源加载阶段,用可能稍长的加载时间来换取游戏过程的极度流畅。 |
💡 默认策略的潜在局限
虽然开箱即用非常方便,但了解其局限性对项目优化至关重要。默认策略主要依赖于对已加载的静态资源和当前渲染设置的分析,这可能导致以下几种情况:
-
预测可能过宽:系统为了确保覆盖率,可能会预测并编译一些在实际游戏中根本不会用到的PSO组合。例如,同一个材质在不同画质设置下会产生变体,默认策略可能会为所有可能的画质等级都编译PSO,即使玩家只会使用其中一种。这会造成额外的内存和CPU时间开销。
-
对动态内容覆盖不足 :这是默认策略的主要盲区。对于在游戏运行时通过代码或蓝图动态生成 的Actor,或者材质在运行时发生动态切换的情况,PSO Precache系统在资源加载阶段无法预知这些变化。因此,这些动态对象所需的PSO将无法被预缓存,只能在首次使用时实时编译,引起卡顿。
-
移动平台性能考量:在移动设备上,CPU核心数和性能通常弱于PC。虽然PSO Precache同样适用,但更长的编译时间可能带来挑战。UE4可能会针对移动平台调整策略,例如跳过一些不常用的渲染状态组合来减少预缓存集的大小,但这可能会增加渲染罕见状态时出现卡顿的风险。
🛠️ 检查与优化建议
为了确保PSO Precache达到最佳效果,您可以进行以下检查和优化:
-
验证预缓存效果 :在非开发版游戏启动时加入命令行参数
-clearPSODriverCache,可以模拟玩家首次运行或更新显卡驱动后的环境。同时,在控制台使用stat PSOPrecache命令可以查看预缓存的统计信息,帮助您了解命中与缺失情况。 -
考虑混合方案 :对于内容相对固定、流程线性的游戏部分,可以继续使用Bundle PSO Cache。通过自动化测试收集PSO使用记录,生成一个高质量的预缓存文件并打包进游戏。然后,可以让PSO Precache作为补充,处理那些无法被Bundle Cache覆盖的边缘情况或动态内容。
-
管理加载预期 :由于PSO Precache将编译工作转移到了加载阶段,关卡初始化时间可能会显著变长。设计清晰的加载界面和提示,管理好玩家的等待预期,是提升体验的重要一环。
希望这些信息能帮助您全面了解UE4中PSO Precache的默认策略。如果您对如何针对您的特定项目进行更深入的优化配置(例如使用Usage Mask)感兴趣,我们可以继续探讨。