type
status
date
slug
summary
tags
category
icon
password
载入
载入是在
FEngineLoop::PreInitPostStartupScreen
中发生OpenPipelineFileCache
逻辑是先从
\Content\PipelineCaches\Windows
载入\Content\PipelineCaches\Windows\XXX_PCD3D_SM5.stable.upipelinecache
接着,检测是否需要
ShouldLoadUserCache()
,这一步说的UserCache就是\Saved\xxx_PCD3D_SM5.upipelinecache
。判断条件是,是否能够开启r.ShaderPipelineCache.LogPSO
,以及r.ShaderPipelineCache.SaveUserCache
这两个flag。

SaveUserCache这个flag默认在mac的shipping版本是开的。对于这两个Flag,在Windows的Shipping版本也有强制开启。

但我个人觉得还是
PSOFileCacheSaveUserCacheCVar.Set(1);
这种方式比较容易不产生怀疑吧。。经过检测,这一调用的源头
RHIInit()
发生在FEngineLoop::PreInitPreStartupScreen()
第2592行,而PreInitPostStartupScreen()
发生在FEngineLoop::PreInit
3648行,在PreInitPreStartupScreen()
之后。说明变量赋值在变量调用之前。所以在shipping版本中,它100%是
_PCD3D_SM5.stable.upipelinecache
+\Saved\xxx_PCD3D_SM5.upipelinecache
组合的结果。退出及保存

保存在
\Saved\xxx_PCD3D_SM5.upipelinecache
。可以看到调用
FShaderPipelineCache::Close()
时会保存:
在析构时保存:

除此之外,运行时也会自动保存:

同样需要开启
r.ShaderPipelineCache.SaveUserCache
这个flag,当然它默认在shipping中是打开的。结论
结论是,载入时,一定会载入
\Content\PipelineCaches\Windows\XXX_PCD3D_SM5.stable.upipelinecache
如果存在的话。如果开了
r.ShaderPipelineCache.LogPSO
和r.ShaderPipelineCache.SaveUserCache
,则还会载入本地缓存的\Saved\xxx_PCD3D_SM5.upipelinecache
。关于保存,如果开启了
r.ShaderPipelineCache.SaveUserCache
,会尝试去保存,是否能保存还取决于 r.ShaderPipelineCache.Enabled
r.ShaderPipelineCache.LogPSO
,结果会保存在\Saved\XXX_PCD3D_SM5.upipelinecache
。触发保存的时机分别在FShaderPipelineCache::Tick()
FShaderPipelineCache::Close()
,FShaderPipelineCache::~FShaderPipelineCache()
以及PipelineStateCacheOnAppDeactivate()
。总结而言,默认是一定会载入
XXX_PCD3D_SM5.stable.upipelinecache
,运行时产生的新PSO会保存在\Saved\XXX_PCD3D_SM5.upipelinecache
,但条件是开启了 r.ShaderPipelineCache.Enabled
,r.ShaderPipelineCache.LogPSO
以及r.ShaderPipelineCache.SaveUserCache
。我认为UE预期shipping版本开启这项保存PSO的功能,同时开发者应该尽量收集更多到PSO到
stable.upipelinecache
中,玩家再帮忙收集一部分做到本地缓存更新\Saved\XXX_PCD3D_SM5.upipelinecache
,就会越来越不卡顿。除此之外,也可以把XXX_PCD3D_SM5.upipelinecache
发给开发者进行合并。那么目前这些功能在Shipping版本可以看到代码里是开的。
验证
Test Build
在Test Build中默认
r.ShaderPipelineCache.LogPSO
和r.ShaderPipelineCache.SaveUserCache
没开,导致在运行时无法存储/生成\Saved\XXX_PCD3D_SM5.upipelinecache
。所以的content里的文件都被加密打包成
.pak
文件,XXX_PCD3D_SM5.stable.upipelinecache
同样在其中,能被成功读入(可从本地log验证)。单纯增加
-logpso
并不会触发保存。一个可行的方案是增加如下命令行参数:
可以在登陆界面通过console检查到对应变量的开启。
然而这一命令却无法触发打开游戏时本地cache的加载,并没有预期之中的
LogRHI: Opened FPipelineCacheFile: ../../../xxx/Saved/XXX_PCD3D_SM5.upipelinecache
。这是因为,由于UE_SHIPPING=0导致两个flag被赋值为0(
>FEngineLoop::PreInitPreStartupScreen()
),紧接着发生了OpenPipelineCache()(PreInitPostStartupScreen()
),此时自然无法读取,推测后面才发生了命令行的flag赋值。结论是,Test Build在代码不做改动的情况下,可以通过增加命令行参数收集PSO,但无法正常载入本地PSO缓存。
Shipping Build
Jenkins上的太慢,本地先build了一个只有登录界面的shipping.
第一次打开客户端,经检查,默认开启两个flag.

检查log,没有发现类似
LogRHI: Opened FPipelineCacheFile: ../../../xxx/Saved/XXX_PCD3D_SM5.upipelinecache
的信息。符合预期,因为全新版本并没有这个本地缓存文件,会生成。
同时在Saved 文件夹中可发现有新创建的
xxx_PCD3D_SM5.upipelinecache
。第二次打开客户端,发现读取本地缓存的Log:

符合预期。
虽然有console可以用很诡异,但我很确定编译时选的是shipping.
接下来直接看看服务器做出的版本吧。。
第一次打开客户端

也新创建了本地缓存

在Haven里逛该之后,准备退出了,看一下目前PSO的情况:

第二次打开客户端,发现读取本地缓存的Log:

在登录界面看PSO的情况:

数目对的上,说明读取成功,没有新增的PSO。
接下来去haven逛该看看涨不涨

只有很微小的两个,主要是因为登陆时碰到了7日礼包界面,真的服咯,再开一遍。

OK,没有新增,证明Shipping版本的PSO载入和保存机制如上所言。注意编版本时一定要选shipping,虽然出来的也有命令行,但Test的PSO是没法读入本地缓存的。
- 作者:Dongfangliu
- 链接:https://www.morningheart.com/article/9b6f3652-0083-42b1-a010-f9035b1bca3a
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。