写入Storage Buffer时为何需在Vulkan着色器中指定Early Fragment Tests?
这种情况完全符合Vulkan规范,属于正常行为,下面分点解释原因:
Storage Buffer写入触发EFT禁用的逻辑
Early Fragment Tests(EFT,即提前深度测试)的核心是在片段着色器执行前就进行深度/模板测试,直接剔除不需要渲染的片段,节省着色器执行开销。但如果片段着色器中包含对可读写资源(比如Storage Buffer)的写入操作,驱动会默认禁用EFT:
原因是硬件无法在EFT阶段回滚已经完成的Storage Buffer写入——如果片段在EFT阶段被剔除,之前执行的Storage Buffer写入操作已经修改了内存状态,无法撤销,这会导致数据逻辑错误。为了避免这种情况,驱动会保守地先执行完片段着色器的所有操作,再进行深度测试。写入
gl_FragDepth.z未触发禁用的原因
按照Vulkan规范,写入gl_FragDepth确实会导致EFT被禁用,因为这会改变深度测试的输入值,无法提前进行测试。但你遇到的情况是驱动做了优化识别:如果你的代码中写入gl_FragDepth.z的值和硬件自动生成的深度值完全一致(比如直接赋值gl_FragDepth.z = gl_FragCoord.z),驱动会判定这个操作没有实际修改深度值,因此仍然允许启用EFT。这种优化是驱动在规范允许范围内的灵活实现,目的是尽可能保留性能。手动启用EFT的注意事项
添加layout(early_fragment_tests) in;确实可以强制驱动启用EFT,恢复帧率,但使用这个限定符时必须注意:
即使片段最终被深度测试剔除,片段着色器中对Storage Buffer的写入操作仍然会执行。这可能导致Storage Buffer中写入了无效的、被剔除片段的数据,破坏你的数据逻辑。只有当你确认:- 所有通过片段着色器的片段都会通过深度测试;
- 即使片段被剔除,写入Storage Buffer的操作是安全或预期的;
才适合使用这个强制启用的限定符。
内容的提问来源于stack exchange,提问作者Zebrafish

