问题描述
从渲染通道提交 srcStageMask/dstStageMask
时可以为 vkCmdPipelineBarrier
设置哪些阶段,因为在这种情况下,没有子通道绑定点到图形管道?
在 subpass 中提交 vkCmdPipelineBarrier
时的相同问题,它具有到计算管道的绑定点,我猜它没有像 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT 这样的阶段,也许还有更多。
谢谢
编辑
首先,感谢@Nicol Bolas 的评论,无法在 subpass 中间调度计算着色器。
我想澄清一下我的问题:
假设我有一个图像,在渲染通道之后将具有 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL 的布局。
renderpass 之后,我想用新数据更新图像,并希望将其布局更改为 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL。
因此,在记录 vkCmdEndRenderPass 之后,我记录了一个 vkCmdPipelineBarrier 命令,如下所示:
const VkImageMemoryBarrier imageMemoryBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
nullptr,
VK_ACCESS_SHADER_READ_BIT, // srcAccessMask
VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessMask
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // oldLayout
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout
VK_QUEUE_FAMILY_IGnorED,
VK_QUEUE_FAMILY_IGnorED,
image,
{ // subresourceRange
VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
0, // baseMipLevel
VK_REMAINING_MIP_LEVELS, // levelCount
0, // baseArrayLayer
VK_REMAINING_ARRAY_LAYERS // layerCount
}
};
vkCmdPipelineBarrier(currentCommandBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,nullptr, 1,&imageMemoryBarrier);
这确保只要渲染过程中的前一个命令仍未跨越片段着色器阶段,过渡就会等待。
但是如果 vulkan 在 renderpass 执行完成后执行 vkCmdPipelineBarrier 呢?现在没有绑定管道,没有阶段 - 这是否意味着屏障将进入无休止的等待,直到新的渲染通道开始并且片段着色器阶段才会发生?
解决方法
只需检查 Valid Usage。
所有这些都是允许的,除了那些在整个设备上禁用其功能的(例如几何着色器),或者队列系列不支持的那些。
对于 subpass 依赖项,仅允许 pipelineBindPoint
管道支持的那些(即目前只有图形)。
我认为让您深感困惑的主要问题是您认为管道是一个有限状态机。但是管道不是 FSM,它是一个管道(顾名思义)。它始终存在(就像它的所有阶段一样),即使当前没有任何东西流经管道。
具体来说,在英语中你的障碍只是简单地说:“在我开始复制到这个图像之后记录的任何命令之前,确保在我完成读取这个图像之前记录的所有命令作为纹理。”
当阶段“存在”不是一个有效的问题时(如上所述);存在和不存在并不是他们真正拥有的属性。正如您在屏障的语义中看到的那样,改变其含义甚至都无关紧要。
某些阶段被有效用法所禁止,但这比减少混乱更重要。即使没有被禁止,也不会改变什么。此类阶段的障碍可能只是无操作,或者在逻辑上会转化为更早或更晚的阶段。
,如果一切正常,那么您要同步的内容如下:
您希望确保在前面的渲染通道完成读取图像之前,图像不会被新数据覆盖。
为了实现这一点,您设置了同步的障碍
Execution: FRAGMENT_SHADER -> TRANSFER
Memory: SHADER_READ -> TRANSFER_WRITE
Layout: SHADER_READ_ONLY_OPTIMAL -> TRANSFER_DST_OPTIMAL
虽然这些同步参数确保了正确性,但它们实际上有点多余。 srcAccessMask
用于需要“使可用”的内存,即~转移到 L2 内存中,以便之后可以访问。
这是你的barrier中不需要的部分,因为内存已经可用(在L2内存中),否则无法正确读取。
即最佳障碍如下:
Execution: FRAGMENT_SHADER -> TRANSFER
Memory: 0 -> TRANSFER_WRITE
Layout: SHADER_READ_ONLY_OPTIMAL -> TRANSFER_DST_OPTIMAL
现在是关于
的问题但是如果 vulkan 在 renderpass 执行完成后执行 vkCmdPipelineBarrier 怎么办?
上面记录的障碍告诉您的 GPU 如下:
- 在当前队列中,等待具有
FRAGMENT_SHADER
阶段的所有前面的命令完成其FRAGMENT_SHADER
阶段,然后再继续其TRANSFER
阶段中的后续命令。
这也意味着:
- 如果队列中没有先前的命令,则屏障的要求已经满足,后续命令的执行可以立即继续。
- 如果队列中有可能不会通过
FRAGMENT_SHADER
阶段的命令,我们不会等待它们。 - 屏障适用于已提交到队列的每个命令。 (但大多数命令将不再处于“执行中”状态,而是已经被删除,因为它们已完成执行。)屏障的
src
依赖项从不指的是可能被提交的东西以后,只针对之前提交过的内容。
如果您对这些事情有困难,您可能想看看 Introduction to Vulkan 讲座,其中涵盖了从 22:28 开始的此类同步主题。