You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单个Cmd Buffer中高效等待两个VkEvent的方法及代码疑问解答

Vulkan事件同步问题解答

问题背景

场景说明

  • 动作1、2、3执行后生成结果OutcomeA,动作4、5、6执行后生成结果OutcomeB
  • 动作7、8仅依赖OutcomeA,不依赖OutcomeB
  • 动作9仅依赖OutcomeB,不依赖OutcomeA

现有代码

// Three dispatches that don’t have conflicting resource accesses
vkCmdDispatch( 1 );
vkCmdDispatch( 2 );
vkCmdDispatch( 3 );

// 4, 5, and 6 don’t share resources with 1, 2, and 3
// No reason for them to be blocked, so set an event to wait for later
vkCmdSetEvent( A, srcStageMask = COMPUTE );

vkCmdDispatch( 4 );
vkCmdDispatch( 5 );
vkCmdDispatch( 6 );

// 7 and 8 don’t use the same resources as 4, 5, and 6.  So use an event
vkCmdSetEvent( B, srcStageMask = COMPUTE );

// 7 and 8 need the results of 1, 2, and 3
// So we’ll wait for them by waiting on A
vkCmdWaitEvents( A, dstStageMask = COMPUTE );
vkCmdDispatch( 7 );
vkCmdDispatch( 8 );

// 9 uses the same resources as 4, 5, and 6 so we wait.
// Also assumed is that 9 needs nothing from 7 and 8
vkCmdWaitEvents( B, dstStageMask = COMPUTE );
vkCmdDispatch( 9 );

疑问

  1. 事件B的作用范围是什么?
  2. 动作9是否会同时等待OutcomeA(动作1、2、3)的结果?
  3. 若答案为“是”(非预期结果),正确的实现方式是什么?

问题解答

1. 事件B的作用范围

事件B的设计意图是标记OutcomeB(动作4、5、6的执行结果)已就绪,原本是给需要依赖OutcomeB的命令提供同步信号。但在当前代码的命令流中,vkCmdSetEvent(B)被放在动作4-6之后、动作7-8的等待命令之前,导致它的触发时机虽然是动作4-6完成后,但后续的命令执行顺序会让它的同步逻辑偏离预期。

2. 动作9是否会等待OutcomeA的结果?

是,这属于非预期结果。Vulkan的命令队列严格按照提交顺序执行,vkCmdWaitEvents(B)排在vkCmdWaitEvents(A)和动作7-8的vkCmdDispatch之后,所以动作9必须等前面所有命令(包括等待OutcomeA完成、执行动作7-8)全部结束后才会启动,相当于间接等待了OutcomeA的结果,完全违背了“动作9仅依赖OutcomeB”的需求。

3. 正确的实现方式

要实现动作7-8仅等OutcomeA、动作9仅等OutcomeB,且两者可以并行执行,有两种常用方案:

方案一:调整单命令缓冲区的命令顺序

把动作9的等待和执行逻辑移到动作7-8的等待命令之前,这样vkCmdWaitEvents(B)只会等待事件B(即动作4-6完成),不会被动作7-8的执行阻塞:

// 执行动作1-3,标记OutcomeA就绪
vkCmdDispatch( 1 );
vkCmdDispatch( 2 );
vkCmdDispatch( 3 );
vkCmdSetEvent( A, srcStageMask = COMPUTE );

// 执行动作4-6,标记OutcomeB就绪
vkCmdDispatch( 4 );
vkCmdDispatch( 5 );
vkCmdDispatch( 6 );
vkCmdSetEvent( B, srcStageMask = COMPUTE );

// 动作9仅依赖OutcomeB,等待B后执行
vkCmdWaitEvents( B, dstStageMask = COMPUTE );
vkCmdDispatch( 9 );

// 动作7-8仅依赖OutcomeA,等待A后执行
vkCmdWaitEvents( A, dstStageMask = COMPUTE );
vkCmdDispatch( 7 );
vkCmdDispatch( 8 );

这种方式下,动作9和动作7-8可以在硬件支持的情况下并行执行,各自只等待自己需要的结果。

方案二:使用多命令缓冲区并行提交

将不同依赖链的命令拆分到独立的命令缓冲区,然后一起提交到队列,实现真正的并行执行:

// 命令缓冲区1:完成动作1-3、4-6并设置事件
VkCommandBuffer cmdBuf1 = ...; // 初始化命令缓冲区
vkCmdBegin(cmdBuf1, ...);
vkCmdDispatch(cmdBuf1, 1);
vkCmdDispatch(cmdBuf1, 2);
vkCmdDispatch(cmdBuf1, 3);
vkCmdSetEvent(cmdBuf1, A, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);

vkCmdDispatch(cmdBuf1, 4);
vkCmdDispatch(cmdBuf1, 5);
vkCmdDispatch(cmdBuf1, 6);
vkCmdSetEvent(cmdBuf1, B, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
vkCmdEnd(cmdBuf1);

// 命令缓冲区2:等待OutcomeA,执行动作7-8
VkCommandBuffer cmdBuf2 = ...;
vkCmdBegin(cmdBuf2, ...);
VkEvent waitEventsA[] = {A};
vkCmdWaitEvents(cmdBuf2, 1, waitEventsA,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                0, nullptr, 0, nullptr);
vkCmdDispatch(cmdBuf2, 7);
vkCmdDispatch(cmdBuf2, 8);
vkCmdEnd(cmdBuf2);

// 命令缓冲区3:等待OutcomeB,执行动作9
VkCommandBuffer cmdBuf3 = ...;
vkCmdBegin(cmdBuf3, ...);
VkEvent waitEventsB[] = {B};
vkCmdWaitEvents(cmdBuf3, 1, waitEventsB,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                0, nullptr, 0, nullptr);
vkCmdDispatch(cmdBuf3, 9);
vkCmdEnd(cmdBuf3);

// 提交三个命令缓冲区到队列
VkSubmitInfo submitInfos[3] = {};
submitInfos[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfos[0].commandBufferCount = 1;
submitInfos[0].pCommandBuffers = &cmdBuf1;

submitInfos[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfos[1].commandBufferCount = 1;
submitInfos[1].pCommandBuffers = &cmdBuf2;

submitInfos[2].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfos[2].commandBufferCount = 1;
submitInfos[2].pCommandBuffers = &cmdBuf3;

vkQueueSubmit(queue, 3, submitInfos, nullptr);

这种方案更灵活,适合复杂的依赖场景,能最大化利用硬件并行能力。


内容的提问来源于stack exchange,提问作者alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:52:09