你的浏览器不支持canvas

让我们携手共创奇迹!

PSO

Date: Author: LBD

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。转载请注明来自WindCrazy

这是一篇关于使用UE的PSO缓存优化安卓应用的一些经验技巧

0、前言

在DrawCall改变GPU渲染状态时会带来额外开销,在头显或配置低的设备体验会更加明显,比如某些材质和特效的首次渲染,或第一次看向资源密集的地方时,会出现明显的卡顿现象。为应对这种难题现代图形API(D3D12、Vulkan、Metal)提供PSO机制来减少硬件改变渲染状态的开销。其原理是把单次渲染所需要的Shader和渲染状态合并成一个对象,称为Pipeline State Object(PSO),由图形API解决各种硬件状态之间的依赖和冗余,给出最优的状态集合和设置方法(称为编译),再统一交给硬件设置渲染状态。

1、机制

PSO (管线状态对象,Pipeline State Object)是在运行时(Runtime)编译生成的二进制代码,运行时编译的二进制代码会被读取回应用程序并缓存为 PSO 缓存。当运行时再次尝试生成相应的 PSO 时,可以直接从 PSO 缓存中进行反序列化读取和加载,从而节省了运行时的编译过程耗时。

具体参考:UE PSO Cache机制、使用与优化

2、用法

要设置你的项目以记录PSO缓存,请执行以下步骤:

  1. 打开项目的 DefaultEngine.ini 或其 (Platform)Engine.ini

(Platform)Engine.ini 文件通常位于 (Project)/Config/(Platform) 目录下。使用此目录可以防止其他可能无需使用PSO缓存的平台获取设置。

  1. Engine.ini 文件中设置以下值:

    [DevOptions.Shaders]
    NeedsShaderStableKeys=true
    
  2. DefaultGame.ini 文件中,设置以下值:

    [/Script/UnrealEd.ProjectPackagingSettings]
    bShareMaterialShaderCode=True
    bSharedMaterialNativeLibraries=True
    
  3. 如果你是从头开始,请确保 (Project)/Build/(Platform)/PipelineCaches 中没有文件。烘焙器会在这个位置寻找记录的缓存文件。如果这是你首次采集PSO,此文件夹可能根本不存在。

  4. 确保控制台变量 r.ShaderPipelineCache.Enabled 设置为1。

    1. 如使用PICO VR设备参考其官方文档:PSO 缓存在 “DefaultDeviceProfiles” 文件中添加 CVar。该文件位于 \ {工程名称} \ Config 路径下,如果没有自行添加。重启后在Device Profiles中看到就可以了
       [Android DeviceProfile]
       DeviceType=Android
       BaseProfileName=
       +CVars=r.ProgramBinaryCache.RestartAndroidAfterPrecompile=0 
       +CVars=r.ShaderPipelineCache.Enabled=1 
       +CVars=r.ShaderPipelineCache.ReportPSO=1 
       +CVars=r.ShaderPipelineCache.StartupMode=1 
       +CVars=r.ShaderPipelineCache.GameFileMaskEnabled=0 
       +Cvars=r.ShaderPipelineCache.LazyLoadShadersWhenPSOCacheIsPresent=1 
       +CVars=r.ShaderPipelineCache.BatchSize=10 
       +CVars=r.ShaderPipelineCache.BatchTime=0.0 
       +CVars=r.Vulkan.PipelineCacheFromShaderPipelineCache=1
      

    收集运行时的PSO并重新打包

    1. {工程名称} \ 工程目录下,新增一个“PSOCaching”文件夹,用来放PSO流程中的各种中间文件后续有用(放哪都可以)。

    2. 打包应用程序,烘焙所有相关地图,然后在 ` {工程名称} \ Saved \ Cooked \ Android_ASTC \ {工程名称} \ Metadata \ PipelineCaches` 路径下找到两个 .shk 文件以及 .upipelinecache文件一并拷贝到PSOCaching。

    3. 在Pico设备上安装刚才打包出来的程序,将命令行参数-logPSO加入UECommandLine.txt,将UECommandLine.txt放在Pico头显文件夹中的UnrealGame \ {工程名称} 目录下,运行该 APK,体验每一个关卡。

      参考:UE5打Android包后执行Command命令

    4. 生成的后缀为 .rec.upipelinecache 的 PSO 缓存在Pico设备的 UnrealGame \ {工程名称}\ Saved \ CollectedPSOs 路径下,将它们拷贝至 PSOCaching 文件夹内。

    5. 在PSOCaching中编写一个 CreateSpc.bat 文件,然后执行它以生成最终打包所需的 *.spc 文件。格式类似于 Engine\Binaries\Win64\UnrealEditor-Cmd.exe [ProjectName] -run=ShaderPipelineCacheTools expand C:\PSOCache\*.rec.upipelinecache C:\PSOCache\*.shk C:\PSOCache\[YourPrefix][ProjectName][ShaderFormatName].spc 示例如下代码所示,具体的引擎、工程目录按照实际情况修改。

        D:\UE5_4\Engine\Binaries\Win64\UnrealEditor-Cmd.exe D:\Projs\PSOTest\PSOTest.uproject -run=ShaderPipelineCacheTools expand D:\Projs\PSOTest\PSOCaching\*.rec.upipelinecache D:\Projs\PSOTest\PSOCaching\*.shk D:\Projs\PSOTest\PSOCaching\PSO0318_PSOTest_SF_VULKAN_ES31_ANDROID.spc
      
    6. 执行bat文件后,会生成一个.spc文件,将.spc添加至 {工程名称} \ Build \ Android \ PipelineCaches 路径下,然后将这个工程重新打包。

    7. 新的 PSO 缓存(* .stable.upipelinecache)位于 {工程名称} \ Saved \ Cooked \ Android_ASTC \ {工程名称} \ Content \ PipelineCaches \ Android 路径下。可以查看文件大小确定PSO是不是正常被打包了

    8. 可以通过日志查看被加载的PSO缓存:

    9. 至此,PSO缓存的应用完成

    10. 注意事项

    11. 收集PSO可以增量收集,但是发生着色器缩量、着色器变化会发生无法预知的问题,需要重新收集

    12. 收集PSO的话,需要按菜单键手动退出。程序崩溃/调用QuitGame函数退出/被踢下线都会导致PSO未能成功收集

    13. 其他

      `NumPrecompilingPSOsRemaining`函数可以查看剩余需要加载的PSO缓存(UE5.6后)
      

3、注意事项

粒子特效如果是GPU模拟的话PSO是录制不上去的,第一次渲染这个粒子还是会卡顿,应该改为CPU模拟

参考

创建捆绑的PSO缓存

UE PSO Cache机制、使用与优化

  1. PSO Caching
    1. PSO Doc:
      1. UE官方文档 - Unreal Engine 5 Android PSO Caching
      2. UE官方文档 - PSO缓存
      3. UE官方文档 - PSO预缓存
      4. UE官方文档 - PSO Precaching
      5. UE官方文档 - 5.4 - 为Android创建捆绑的PSO缓存
      6. UE官方文档 - 5.5 - 为Android创建捆绑的PSO缓存
      7. Tom Looman - Setting up PSO Precaching & Bundled PSOs for Unreal Engine
      8. PSO 缓存 - PICO
    2. PSO Video:
      1. YouTube - PSO Caching in UE4.27 to reduce hitching in Android
      2. [[UFSH2024]虚幻引擎移动端开发最新进展 Jack Porter Epic Games 引擎移动平台开发主管](https://www.bilibili.com/video/BV18F2oYAEJ4?spm_id_from=333.788.videopod.sections&vd_source=30b5d6dd5435961e25b24fcc71e401d8)
  2. PSO Pre-caching
    1. 采用PSO预缓存方式,在尽可能早的时间,预加载当前场景物体所有可能关联的物体的PSO(存在一些预测算法)
    2. PSO预缓存方式目前5.6版本才有,且不支持Mobile

对于本文内容有问题或建议的小伙伴,欢迎提出问题