UE5.5.3版本,PSOPrecaching打开后,很多绘制并未执行异步PSO编译造成卡顿

现象简述是:Iphone真机在进入战斗场景时,有以秒为单位的大卡顿,Insight数据看的结果是RenderThread被大量的PipelineState Time卡住了。

目前关于PSOPreching的关键配置如下,并且确认是生效的

r.PSOPrecaching=1

r.PSOPrecache.Components=1

r.PSOPrecache.Resources=0

r.PSOPrecache.Mode=0

r.PSOPrecache.ProxyCreationWhenPSOReady=1

r.PSOPrecache.ProxyCreationDelayStrategy=1

r.PSOPrecache.DrawnComponentBoostStrategy=1

因为项目是研发中,并不想去做繁杂的老版本离线收集编译的方式,能接受在不卡顿的情况下出现显示延迟。

实际上此配置在平时测试关卡和大厅关卡中都正常执行了,即反复多次出现先显示灰白格(DefaultMaterial)数秒后正常显示。

但在进入正式战斗场景时,出现了巨大卡顿,此功能看起来是部分失效了。

[Image Removed]之所以说部分失效是因为从Insight数据可以看出,此卡顿帧执行了136次PSO编译,走异步的只有54次,另外79次都在同步造成RenderThread卡顿。

不知道是什么原因,从PSOPreching功能介绍应该是全部走异步PSO编译的,DrawImmediate下有默认材质顶着才对。

有一些猜想

1.虽然时机是进入场景渲染场景的一瞬间,但实际上应该也有其他各种类型的第一次绘制,是否某些绘制无法触发异步PSO?

2.是否某些潜规则或者特殊流程是无法走异步PSO的?

考虑真机联调Debug引擎来查这个问题但是麻烦度有点高,于是先请教一下有可能是什么原因或者有没有高效Debug这个问题的建议?

补充一些现象,在战斗过程中也发现一些PSO相关卡顿,看起来更像是某些绘制并没有触发异步PSOCache。

同样一局Trace,同样在各种战斗情况中出现需要PSO编译

有时候成功异步了,表现是先出现灰色默认材质,0.5秒后正常渲染,渲染线程完全不会卡。比如:

[Image Removed]

有时候就没有执行任何一个PSOPrecompilePool线程,直接渲染线程同步卡顿了:

[Image Removed]

Hi,

我不能100%确定,只是觉得可能是因为Render Thread此时在等Mesh Pass Setup的Task结束,等待的过程中,我感觉TaskGraph会尝试执行一些task,而FCompilePipelineStateTask在bPSOPrecache是false的情况下,可能会用AnyThread,导致Render Thread上执行了编译工作。

能否尝试一下把InternalCreateGraphicsPipelineState里的!bPSOPrecache去掉,从而让编译任务都发动到thread pool里工作?

恩。我后面还是简单跟了一下源码,是有打算​强制改一波InternalCreateGraphicsPipelineState让这个全走PsoPrecompilePool线程,只是不确定会不会导致其他什么连锁反应这两天会试试…

还有个问题是:这一块的Debug功能有点混乱,文档中关于这个的介绍里混了老版本的离线收集、PC的PSOCache,Mobile的PSOCache三个功能。很难分辨各种CVar指令或者调试指令哪些才是真正Mobile平台PSOPreCache,这一块有没有什么调试方面的经验建议呢?

能否把有问题和没问题的trace文件发上来我也看一下?我想确认一下RenderThread是否是在等MeshDrawCommandPassSetupTask,而他还没有被执行,所以开始做一些其他的task。

如果单看IOS平台,PSO Precaching功能和ShaderPipelineCache应该不会同时起效(r.Metal.EnablePSOFileCacheWhenPrecachingActiv),所以默认应该只有PSO Precaching。

1.继续Debug了一下,看起来像是因为PrecachePSOs()这个方法虽然执行了但是漏掉一些PSO,之后由渲染触发(应该是算miss?)就走同步了。从一些现象上来看有跟出现PointLight后miss的,有ComputeShader是miss的,根据r.PSOPrecache.Validation打开后输出结果还有原因是RT不同导致PSO不同miss的。现在问题就是数量有点多,不太确定能不能每个都处理好把这个同步卡顿问题解决。

2.把InternalCreateGraphicsPipelineState的bPSOPrecache去掉,在IOS平台上依然有很多RenderThread执行的同步CompilePSO,这个我还得继续看下为什么。这里还是期望有办法改成就算渲染触发也走异步且不wait,宁愿这次绘制跳过。

3.trace文件多多少少带了一些项目相关的路径或者资源名之类的,Upload File不太方便,有什么私信的办法么(企业微信/微信/邮箱等等?

感谢提供信息,

  1. 如果是miss的,除了想办法修改预测的地方,也可以打开r.SkipDrawOnPSOPrecaching 1试试
  2. IOS平台可能IsAsyncCompilationAllowed是返回false的,因为默认没有开RHI Thread,Fortnite在核较多的IOS设备上开启了(应该超过2个大核就可以)。
  3. 关于confidential的信息,可以把这个case转成 confidential的,这样这个case就只有你们的账号才能看到,可以上传trace。

如果还是有担心,可以发到我的邮箱wei[Content removed],我可以先确认一些信息。

utrace文件已经发送。

RHIThread刚好我这边debug发现了5.5.3版本需要多设置个r.Metal.IOSRHIThread=1,才能在IOS平台成功打开。

好的,忘记提示这个Cvar的名字了,麻烦确认一下开启r.SkipDrawOnPSOPrecaching=1和r.Metal.IOSRHIThread=1后,看看这个问题是不是就没有了。

都试过了不行,并且都是XCode联调引擎跑的,细节如下:

1.r.Metal.IOSRHIThread=1打开RHI后是有变化的,之前由Draw触发的CompilePSO是RenderThread上同步执行的,现在因为打开RHI后这些PSO编译确实是异步执行了,但由Draw触发的这些Task会让RHIThread在Wait他们Complete。实际上只是多线程加速,效率提高了稍微缓解了一点,依然RHIThread有卡顿。

2.r.SkipDrawOnPSOPrecaching=1这个没啥用,开了毫无变化,Debug了下具体实现代码中:

if (bAllowSkipDrawCommand && GSkipDrawOnPSOPrecaching && PSOPrecacheResult == EPSOPrecacheResult::Active)

{

return false;

}

无法执行到里面去,因为这里的PSOPrecacheResult要么是EPSOPrecacheResult::Compelete要么是EPSOPrecacheResult::Missed,都没出现 EPSOPrecacheResult::Active

感谢反馈,看了一下代码,确实是只有这个PSO做了PreCaching,上面的​GSkipDrawOnPSOPrecaching的功能才能起效…,所以只能查一下这些mesh的Shader为什么没有在PSOPrecaching的时候被创建。(我记得log里应该有提示)另外可以debug一下UPrimitiveComponent::PrecachePSOs