Vulkan间接计算调度内存屏障配置报错与缓冲区更新不生效问题
问题核心原因
你遇到的问题完全是内存屏障的阶段掩码与访问掩码不匹配导致的,Vulkan规范本身没有矛盾,是你对间接调度的执行阶段理解有误。
vkCmdDispatchIndirect读取间接缓冲区参数的操作,不属于VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT阶段,而是明确属于VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT阶段。这个阶段名里的「DRAW」属于历史命名惯性,实际覆盖所有间接类命令的参数读取流程,包括计算间接调度、光线追踪间接构建等所有间接命令。- 你最初的屏障
dstAccessMask只写了VK_ACCESS_SHADER_READ_BIT,对应的是计算着色器代码里主动读缓冲区的操作,而间接调度读参数的操作是驱动在调度命令执行前、在DRAW_INDIRECT阶段完成的,根本不会触发SHADER_READ的访问权限,所以屏障完全没生效,第二个调度读到的还是初始化的x=0。 - 你后来给
dstAccessMask加了VK_ACCESS_INDIRECT_COMMAND_READ_BIT后功能正常,是因为访问掩码终于覆盖了实际的读操作,但你此时的dstStageMask还是VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,和INDIRECT_COMMAND_READ要求的DRAW_INDIRECT阶段不匹配,所以触发了验证层报错。
正确的屏障配置
修改屏障的阶段掩码即可,完整配置如下:
VkBufferMemoryBarrier barrier; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; // 源阶段:第一个计算着色器写缓冲区的阶段 barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; barrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; // 目标阶段:间接调度读取命令参数的阶段 barrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; barrier.dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; // 其余配置不变 barrier.srcQueueFamilyIndex = queue_idx; barrier.dstQueueFamilyIndex = queue_idx; barrier.buffer = indirect_buffer; barrier.offset = 0; barrier.size = sizeof_indirect_buffer; // 提交屏障 vkCmdPipelineBarrier( cmd_buffer, barrier.srcStageMask, barrier.dstStageMask, 0, 0, nullptr, 1, &barrier, 0, nullptr );
额外说明
如果你的第二个计算着色器本身也会读取这个indirect_buffer的内容,才需要在dstAccessMask里同时加上VK_ACCESS_SHADER_READ_BIT,且dstStageMask需要同时包含VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,保证两个阶段的读操作都能拿到正确的数据。
内容的提问来源于stack exchange,提问作者alagris
相关产品推荐
相关产品推荐

