UE4中使用PSO缓存优化

1、简述

在首次进入项目时,第一次加载新场景,或打开RT缩略图的卡顿;在第二次进入游戏后不会,实则是编译新着色器时项目出现的卡顿耗时,可以通过PSO缓存方式优化加载时间:

UE 中的 PSO Caching 机制,用于预先记录和构建出运行时所使用的材质依赖的 Shader 信息,当项目首次使用这些 Shader 时,该列表可以加速 Shader 的加载 / 编译过程。PSO Caching 会把渲染状态、顶点声明、Primitive 类型、RenderTarget 像素格式等数据保存到文件中,提升 Shader 的加载效率。

相关官方介绍:PSO缓存 | 虚幻引擎文档 (unrealengine.com)

2、构建流程

  1. DefaultEngine.ini修改,在执行Cook时生成稳定的ShaderKey,作为记录Shader的凭据并打包
[DevOptions.Shaders]
NeedsShaderStableKeys=true
  1. 打包会生成2个scl.csv 对应项目、引擎,可以查看到有10w+cook项

  2. 配置里加入并打包

[ConsoleVariables]
r.ShaderPipelineCache.Enabled=1
r.ShaderPipelineCache.LogPSO=1
r.ShaderPipelineCache.SaveBoundPSOLog=1

启动游戏,运行会在手机生成.upipelinecache(运行时捕获的PSO数据)
此处PSO采集尽可能的多会有助于生成的数据全面
android下可以在内部存储-\Android\data\YourGame\files\UE4Game\YourGameName\YourGameName\Saved获取
ios下由于其沙盒机制,不可直接访问文件,可以连接mac后,打开xcode下载Container获取
4. 根据上述3个文件,放入C:/PSOCaching写.bat脚本,使用UE4Editor-Cmd.exe生成.stablepc.csv
android内容如下:

YourEnginepath\UnrealEngine\Engine\Binaries\Win64\UE4Editor-Cmd.exe YourProjectpath.uproject -run=ShaderPipelineCacheTools expand C:\PSOCaching\*.rec.upipelinecache C:\PSOCaching\*.scl.csv C:\PSOCaching\YourProjectName_GLSL_ES3_1_ANDROID.stablepc.csv

ios内容如下:

C:\Project\Z_Plan\Project_G_Engine\UnrealEngine\Engine\Binaries\Win64\UE4Editor-Cmd.exe C:\Project\Client_ZPlan\Project\YourProjectName.uproject -run=ShaderPipelineCacheTools expand C:\PSOCaching_IOS\*.rec.upipelinecache C:\PSOCaching_IOS\*.scl.csv C:\PSOCaching_IOS\YourProjectName_SF_METAL_IOS.stablepc.csv
  1. stablepc.csv 放到本地的Build/Android/PipelineCaches下再次进行打包,引擎在Cook时通过stavlepc.csv创建PipelineCache,如此一来,新的pak包就可以读取加载PSO缓存。
  2. 如何最小成本放到项目中去,即作为一个资源,可以将流程的5略过,进行如下调整,把本质上引擎内的commandlet拿出来,可参考引擎中的ShaderPipelineCacheToolsCommandlet.cpp,执行BuildPSOSC来生成.stable.upipelinecache追加一个bat脚本如下:
    android内容如下:
YourEnginepath\UnrealEngine\Engine\Binaries\Win64\UE4Editor-Cmd.exe YourProjectpath.uproject -run=ShaderPipelineCacheTools build "YourProjectpatht\Build\Android\PipelineCaches\*YourProjectName_GLSL_ES3_1_ANDROID.stablepc.csv" "YourProjectpath\Saved\Cooked\Android_ETC2\YourProjectName\Metadata\PipelineCaches\ShaderStableInfo-Global-GLSL_ES3_1_ANDROID.scl.csv" "YourProjectpath\Saved\Cooked\Android_ETC2\YourProjectName\Metadata\PipelineCaches\ShaderStableInfo-YourProjectName-GLSL_ES3_1_ANDROID.scl.csv" "YourProjectpath\Saved\Cooked\Android_ETC2\YourProjectName\Content\PipelineCaches\Android\YourProjectName_GLSL_ES3_1_ANDROID.stable.upipelinecache"

ios内容如下:

C:\Project\Z_Plan\Project_G_Engine\UnrealEngine\Engine\Binaries\Win64\UE4Editor-Cmd.exe C:\Project\Client_ZPlan\Project\YourProjectName.uproject -run=ShaderPipelineCacheTools build "C:\Project\Client_ZPlan\Project\Build\IOS\*YourProjectName_SF_METAL_IOS.stablepc.csv" "C:\Project\Client_ZPlan\Project\Saved\Cooked\IOS\*.scl.csv" "C:\PSOCaching_IOS\YourProjectName_SF_METAL.stable.upipelinecache"

这样会生成一个.upipelinecache,放进项目里的Content\PipelineCaches\platform下面,这样就可以作为一个资源进行打包和热更了,最终实现效果与步骤5一致。
最终区分平台保存upipelinecache资源后的路径如下:
Content\PipelineCaches\Android\YourProjectName_GLSL_ES3_1_ANDROID.stable.upipelinecache
Content\PipelineCaches\IOS\YourProjectName_SF_MTEAL.stable.upipelinecache

3、测试结果

以下为安卓独立app,实测同一场景下多次测试下的平均值:(上下略有误差在100ms以内)数据可以作为参考,实际优化的多少视你项目场景的复杂性而定。
首次进入游戏

打开页面总耗时(ms)加载小地图0用时(ms)加载小地图1用时(ms)加载小地图2用时(ms)加载小地图3用时(ms)
2793.01192.0238.0821.0536.0

清空缩略图本地缓存后

打开页面总耗时(ms)加载小地图0用时(ms)加载小地图1用时(ms)加载小地图2用时(ms)加载小地图3用时(ms)
1349.0334.091.0534.0384.0

使用PSO Cache首次进入游戏,(与清空缓存后打开几乎没有差别)

打开页面总耗时(ms)加载小地图0用时(ms)加载小地图1用时(ms)加载小地图2用时(ms)加载小地图3用时(ms)
1267.0340.078.0504.0341.0


本地有缩略图缓存下
打开页面:114ms

模拟资源更新
以上为打包为apk测试结果,为模拟热更资源效果是否生效,即跳过步骤5,6进行打包,手机安装完成后,将upipelinecache资源手动复制到手机缓存路径下的Content\PipelineCaches\Android
再次进行测试,结果与上述一致,说明该资源可经过热更达到优化效果

4.更改路径和热更:

为了符合不同项目的需求,可以考虑从几个方面进行修改:即PSO启动顺序、项目名称、项目路径的更改,来保证后续资源热更到自己想要的路径之下。
由流程可知,最终我们需要的upipelinecache放进了项目里的Content\PipelineCaches\Android下面,
引擎在启动时加载PSO Cache,会执行OpenPipelineFileCache函数,这里的路径在引擎写死,即读取路径为content/PipelineCaches/PlatformName,如下:

FString GamePathStable = FPaths::ProjectContentDir() / TEXT("PipelineCaches") / ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName()) / FString::Printf(TEXT("%s_%s.stable.upipelinecache"), *FileName, *PlatformName.ToString());

想要实现更改,需要做如下步骤:
1、配置文件中限制引擎启动时就会自动加载PSO Cache,并且添加你自己的项目名称ProjectName

[ConsoleVariables]
r.ShaderPipelineCache.Enabled=0
r.ShaderPipelineCache.LogPSO=0
r.ShaderPipelineCache.SaveBoundPSOLog=0
r.ShaderPipelineCache.ProjectName=YourGameName

2、在进入游戏后,再手动执行引擎内的Load函数:在脚本文件中加入:(当然这些原生自C++,可以用任意语言调用即可)

UE4.UFlibShaderPipelineCacheHelper.EnableSaveBoundPSOLog(true)
UE4.UFlibShaderPipelineCacheHelper.EnableShaderPipelineCaches(true)
UE4.UFlibShaderPipelineCacheHelper.LoadShaderPipelineCache("YourGameName")

3、在引擎侧修改,当项目名称为项目时的路径特殊处理:

//读取配置中的ProjectGName
FString ProjectName;
GConfig->GetString(TEXT("ConsoleVariables"),TEXT("r.ShaderPipelineCache.ProjectName"),ProjectName,*GEngineIni);

if (FileName == ProjectName)
{
   GamePathStable = FPaths::ProjectContentDir() / TEXT("YourGamePath/PipelineCaches") / ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName()) / FString::Printf(TEXT("%s_%s.stable.upipelinecache"), *FileName, *PlatformName.ToString());
   GamePath = FPaths::ProjectContentDir() / TEXT("YourGamePath/PipelineCaches") / ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName()) / FString::Printf(TEXT("%s_%s.upipelinecache"), *FileName, *PlatformName.ToString());
}

经过测试,最终情况为:
在进入项目后(而非引擎启动时)加载PSO,并可以经过热更在content/YourGamePath/PipelineCaches/PlatformName下生效。

5.总结:

可以看出使用PSO 缓存优化可以解决首次进入游戏,减少材质需要编译新着色器时项目可能出现的卡顿问题。
代价:理论上由于需要打包额外的PipelineCaches,需要牺牲磁盘空间,测试下独立app下磁盘上升约100kb,缓存列表主要充当字典,故上升的磁盘空间不多,大小主要受到流程3中运行时捕获的PSO数据影响。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值