Hello,
我们在最近的调查 UE 4.27.2 Cascade 的 GPU 粒子性能问题的过程中,发现了一处可能与 Resizable BAR 机制相关的 CPU 性能异常,希望能求教一下。
在UE引擎中,当其进行Particle GPU Simulation的初始化时,会在 Engine/Source/Runtime/Engine/Private/Particles/ParticleGpuSimulation.cpp 内的 BuildParticleVertexBuffer() 函数中对Dynamic VertexBuffer 进行填充。其实现方式是将包含多重for循环的填充代码写在了对VertexBuffer进行Lock与Unlock操作之间。并且部分机器上我们观察到了相关的严重掉帧情况(AMD CPU+5070发现存在问题,Intel CPU+3080则不存在问题,暂不确定还有哪些组合存在此问题)。在 UE 5.6 中相应的代码似乎并没有改变。<br/>
我们做了以下尝试,均可使 CPU 性能问题消失:
- 事先分配一段内存让多重for循环对其进行填充,在Lock/Unlock之间只执行一次内存拷贝操作,性能问题不再出现。
- 将ReBAR功能使用 NVIDIA Profile Inspector 禁用,性能问题也不再出现。
此外,我们在UE引擎代码中还发现了多处类似的情况,不确定它们对游戏性能是否也会产生程度上与写入频次有关的负面影响。
想向Epic询问一下此问题的优化建议,以及是否建议对于UE 4.27制作的游戏,在驱动内的游戏Profile中禁用ReBAR?如果禁用ReBAR,是否会有什么潜在的风险/副作用?
谢谢!
Liu.Wei
(Liu.Wei)
2
Hi,
你好,我不太确定Resizable BAR机制跟底层驱动是否有什么关系,但是我估计RHI层应该感知不到这个功能的开关。关于你做的尝试,我有两个问题:
- 第一个方案,是指通过一次memcpy,直接将一段准备好的buffer copy到RHILock的Buffer上吗?我无法看出这两种写法的差异,对于RHI层应该是一样的,不过如果你确定有效,就可以保留这种方式。
- 禁用ReBAR应该只是为了验证跟他有关吧,游戏内应该没有API之类的可以关闭吧?另外能问一下你是怎么跟ReBAR联系在一起的呢?
对于改善RHILockVertexBuffer性能,UE5其实是做了优化的,UE4的版本是用的ImmediateRHICommandList,所以必须是在RenderThread上线性执行,UE5的版本接口改造过,可以使用RHICommandList,达到多线程执行。不过我估计不太适合现在移植到UE4,因为改动相对比较大。
另外UE4里D3d12的LockBuffer应该还有一个潜在的bug,可以看一下这个改动https://github.com/EpicGames/UnrealEngine/commit/def03b5cfede549af928a6b5f6b764a38428ba4a
所以如果方式1确实能解决问题,可以保留,应该没有什么风险。
Hello,
非常感谢刘老师的迅速解答!
我们深入调查了一下,我们遇到的 BuildParticleVertexBuffer() 性能问题似乎更多地源于一个项目内部的问题,导致 BuildParticleVertexBuffer() 内 FFloat16::SetWithoutBoundsChecks() 内的 Bitfield 操作对 RHILockVertexBuffer() 返回的 Upload Heap 内存进行了读取操作,而 Upload Heap 内存读取性能奇差(目前还是不确定是特定 CPU 的 Write-combine 特性,还是 Upload heap 在 ReBAR 下直接使用了显存映射的原因)。这应该是一个个例,不影响 Vanilla engine。还是非常感谢你们的帮助!