5.3.2存在pso重复编译的问题,麻烦确认一下。

5.3.2存在pso重复编译的问题,麻烦确认一下。

* 配置以下开关,不做postload触发的precache,将Mesh相关的pso编译延迟到MeshDrawCommand::SubmitDrawBegin(…)中:

r.SkipDrawOnPSOPrecaching=1

r.PSOPrecache.Components=0

r.PSOPrecache.Resources=0

r.PSOPrecache.ProxyCreationWhenPSOReady=0

* 表现:如下图,MI_FireArrowBurN_06(2670518295)在不同的线程上被编译了两次;(前面是pso对应的材质名、后面是对应FGraphicsPipelineStateInitializer的hash);

[Image Removed]

* 推测的原因:

RDG使用FParallelMeshDrawCommandPass::DispatchDraw(…)并发处理FDrawVisibleMeshCommandsAnyThreadTask任务时,每个任务最终都会进入FMeshDrawCommand::SubmitDrawBegin(…)。这个方法没有做线程同步。虽然它调用的RetrieveAndCachePSOPrecacheResult(…)、PipelineStateCache::CreateGraphicsPipelineStateAsync(…)内部有做局部范围的同步,但考虑以下情形,仍然会造成pso重复编译:

* FDrawVisibleMeshCommandsAnyThreadTask的两个实例TaskA、TaskB中,对应MeshDrawCommand对应的FGraphicsPipelineStateInitializer是相同的;

* TaskA被分派到线程Background#1、TaskB被分派到BackGround#2,两者并发执行;

* TaskA&B同时进入RetrieveAndCachePSOPrecacheResult(..),执行下图的逻辑:

[Image Removed]

* 两个任务获取的状态都是Missed,因此会各自调用SetGraphicsPipelineState(…),从这里一直到FPSOPrecompileTask->CompilePSO()的执行,都没有做任何检测或同步的,意味着同样的pso可能会被编译多次;

[Image Removed]

Hi,

你好,的确会有这种情况发生,我想问一下为什么你们选择不在postload的时候precache pso?因为precaching这个系统的基础就是为了在postload的时候来提前编译pso,如果跳过的话,它后续的功能就会出现现在这种情况。它并没有考虑这种情况要如何保证编译任务的去重。如果在GetAndOrCreateGraphicsPipelineState里加锁,应该会比较严重的影响并行性。

postload里加了也会有这个问题发生,precache预测式的收集本来也不准。此外GetOrCreateGraphicsPipelineState中操作的cache用的都是tls对象(在帧结尾才会合并、剔除相同的),对不同线程发起的编译请求加了锁也没用

如果打开Resource和Component的PreCaching,应该能规避掉因为并行渲染造成的重复编译PSO的情况(当然要能提前预测到用到的PSO),precache的确会编译比实际需求更多的pso,不过它编译的都是不同的permutation,不会造成相同的pso重复编译。

另外我说的加锁主要是针对GGraphicsPipelineCache,这个应该不是tls对象。