Vulkan中正在使用的描述符集内未被引用的数组成员可否单独更新
结论
你的理解不符合Vulkan规范,你描述的更新索引28描述符的操作完全合法,不存在未定义行为。
规范判定规则
Vulkan对描述符更新的冲突判定是条目级粒度的,从来没有“描述符集被GPU占用就不能修改任何内容”的全局限制:
仅当你更新的单个描述符条目,已经被提交到队列、尚未执行完成的GPU命令实际访问时,这次更新才会触发写入冲突导致未定义行为。
你配置的绑定参数如下:
binding = 0; descriptorCount = 8192; descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
在你说的场景里,所有已提交的GPU命令只会访问该数组0-16区间的元素,索引28的条目从未被任何待执行命令引用,哪怕整个描述符集正被GPU使用,更新这个条目也没有任何合规性问题,不需要等整个描述符集执行完毕,也不需要为了单个元素重新分配整套描述符。
所谓“绑定中的描述符集不能更新”是从OpenGL遗留下来的错误认知,OpenGL旧实现因为驱动层的全局状态管理设计才有这个限制,Vulkan从核心规范层面就支持bindless架构下的细粒度描述符更新。
落地该方案的实用建议
你选的单一大描述符数组、着色器直接索引采样的方案是目前业界降低描述符绑定开销的标准实现,逻辑简洁性能也好,实际用的时候注意几个点就能避开同步问题:
- 不要零散等围栏做同步:给描述符条目做基于帧的环形分配即可。比如你的交换链深度是3,就把当帧提交使用的条目标记为存活,等3帧后对应帧的执行围栏触发,再批量回收这一批条目更新新的纹理内容,整个过程和你现有的帧同步逻辑重合,不会带来额外阻塞开销。
- 新资源优先占用从未使用过的空条目,等空条目耗尽后,再回收超过最长存活周期、确认没有任何待执行命令引用的老条目,不要随意复用可能被访问的条目。
- 不需要特意开启
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT扩展也可以做上述更新:这个扩展的作用是允许你更新正在被待执行命令引用的条目(需要额外加内存屏障保证同步),你更新从未被引用的条目的行为属于核心规范覆盖的范围,不需要依赖扩展。 - 极少数老旧移动端驱动存在实现bug,会在描述符集被绑定后锁定整个集的更新,遇到这种情况只要多分配几套描述符集轮询使用做兼容即可,不属于规范要求的约束。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

