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::PreInit3648行,在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 许可协议,转载请注明出处。
