我们最近在合Epic p4上的一些修复36229276,44931331,34369995,32679349,32854759,34132292,然后提交给AI做Review后发现3个问题,让AI检查了了一下当前UE5Main官方代码是否有同样的问题,AI回复好像问题也是有的;
这三个问题分别是:
1. [Critical] VulkanMemory.cpp — FTempBlockAllocator 不能真正 grow
确认存在问题。
VulkanMemory.cpp:4780 的断言写错了:
checkfSlow(BlockAlignment < BlockSize, TEXT(“… size of %d (%d aligned) is too large for block size of %d”), InSize, AlignedSize, BlockSize);
条件是 BlockAlignment < BlockSize,这是一个静态恒真条件(alignment=16 < blockSize=4MB 永真),应该是 AlignedSize <= BlockSize。这意味着:
- 超过 BlockSize 的请求永远不会被拦截
- fetch_add(AlignedSize) 会让 CurrentOffset 超出 block 边界
- AllocOffset + InSize < BlockSize 失败后进入加锁路径,分配一个新的同样 BlockSize 大小的 block — 还是放不下
- 最终命中 checkSlow(AllocOffset + InSize < BlockSize) (line 4823),但这只在 Debug slow-check 构建中触发
- Release/Shipping 构建中直接越界写入 → GPU fault 风险
另外 AllocBlock() (line 4746) 始终用固定 BlockSize 创建 buffer,没有任何 grow 逻辑。
2. [High] VulkanBuffer.cpp — Lock 的 else 分支不保留旧数据
确认存在问题。
VulkanBuffer.cpp:431-449,Lock 函数的 else 分支:
FBufferAlloc NewAlloc;
AllocateMemory(NewAlloc); // 全新 buffer,内容未初始化
NewAlloc.Alloc.Disown();
// … swap in on RHI thread, free old buffer
Data = NewAlloc.HostPtr;
DataOffset = Offset;
这个分支在以下条件触发:dynamic/unified buffer,非首次 lock,WriteOnly 模式(非 NoOverwrite),非 staging 强制,非 sparse。它会直接替换整个 backing store。
如果是 partial lock(Offset != 0 或 LockSize != GetSize()),新 buffer 中未被写入的区域是脏数据/未初始化内存。虽然 RLM_WriteOnly 契约通常隐含 discard,但如果上层代码依赖保留 buffer
的前/后部分(比如只更新后半段),就会出现随机渲染错误。
实际触发概率取决于上层使用模式,但代码层面确实缺乏防御——没有 assert 检查 partial lock,也没有 copy-on-write。
3. [High] VulkanBuffer.cpp — staging copy 前缺 barrier
确认存在问题。
VulkanBuffer.cpp:505,Unlock 的 staging copy 路径,copy 前只有:
VulkanRHI::DebugHeavyWeightBarrier(CommandBufferHandle, 16); // 非 Debug 构建为空操作
而 DebugHeavyWeightBarrier 的定义在 VulkanRHIPrivate.h:631-637:
inline void DebugHeavyWeightBarrier(VkCommandBuffer CmdBuffer, int32 CVarConditionMask)
{
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
if (CVarVulkanDebugBarrier.GetValueOnAnyThread() & CVarConditionMask)
{
HeavyWeightBarrier(CmdBuffer);
}
#endif
}
在 Shipping/Test 构建中编译为空。copy 后的 BarrierAfter(line 515-516)保留了,但 copy 前没有真正的 read→write 依赖保护。如果之前有 GPU 操作在读这个 buffer,staging copy 可能与之并行执行,产生
WRITE_AFTER_READ hazard。
截图中提到之前加的 SYNC-HAZARD-WRITE-AFTER-READ fix 被这次合并直接移除了,Shipping 构建有 sync hazard 回归风险。
[Attachment Removed]