Vulkan - 在 vkCmdPipelineBarrier 命令中设置的渲染过程中存在 "stages"

Vulkan - what "stages" exist out of a render pass for setting in vkCmdPipelineBarrier command

提交 vkCmdPipelineBarrier 渲染通道外的 srcStageMask/dstStageMask 时可以设置哪些阶段,因为在这种情况下没有子通道绑定点到图形管道?

在子通道中提交 vkCmdPipelineBarrier 时的相同问题,该子通道具有到计算管道的绑定点,我猜它没有像 VK_PIPELINE_STAGE_VERTEX_SHADER_BIT 这样的阶段,也许还有更多。

谢谢

编辑

首先,感谢@Nicol Bolas 的评论,无法在子通道中间调度计算着色器

我想澄清一下我的问题:

假设我有一个图像,在渲染过程之后将具有 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,
                     0, nullptr,
                     0, nullptr,
                     1, &imageMemoryBarrier);

这确保只要 renderpass 中的先前命令仍未穿过片段着色器阶段,过渡就会等待。

但是,如果 vulkan 在 renderpass 执行完成后执行 vkCmdPipelineBarrier 怎么办?现在没有绑定管道,没有阶段 - 这是否意味着屏障将进入无休止的等待状态,直到新的渲染通道开始并且片段着色器阶段将发生?

只需检查 Valid Usage.

所有这些都是允许的,除了那些在整个设备上禁用其功能的(例如几何着色器),或者那些队列系列不支持的。

对于子通道依赖项,只允许 pipelineBindPoint 管道支持的那些(即目前只有图形)。


我认为让你深感困惑的主要问题是你认为pipeline是一个有限状态机。但是pipeline不是FSM,是pipeline(顾名思义)。它始终存在(就像它的所有阶段一样),即使当前没有流经管道。

具体来说,您的屏障用英语简单地说:“在我开始将此图像复制到此图像之后记录的任何命令之前,请确保在我完成读取此图像之前记录的所有命令作为纹理。”

当阶段“存在”不是有效问题时(如上所述);存在与不存在并不是他们真正拥有的属性。正如您在障碍的语义中看到的那样,改变它的含义甚至都没有关系。

某些阶段被有效用法所禁止,但这更多的是为了减少混淆。即使他们不被禁止,也不会改变任何事情。这些阶段的障碍将只是无操作,或者会转化为逻辑上更早或更晚的阶段。

如果我没看错,那么你要同步的是:
您希望确保在前面的渲染通道完成读取图像之前,图像不会被新数据覆盖。

为此,您设置了同步障碍

Execution:   FRAGMENT_SHADER            ->   TRANSFER
Memory:      SHADER_READ                ->   TRANSFER_WRITE
Layout:      SHADER_READ_ONLY_OPTIMAL   ->   TRANSFER_DST_OPTIMAL

虽然这些同步参数确保了正确性,但实际上它们有点多余。 srcAccessMask 用于需要“可用”的内存,这意味着 ~ 转移到 L2 内存中,以便以后可以访问它。

这是你的屏障中不需要的部分,因为内存已经可用(在L2内存中),否则无法正确读取。

即最佳障碍如下:

Execution:   FRAGMENT_SHADER            ->   TRANSFER
Memory:      0                          ->   TRANSFER_WRITE
Layout:      SHADER_READ_ONLY_OPTIMAL   ->   TRANSFER_DST_OPTIMAL

现在回答关于

的问题

But what if vulkan executes vkCmdPipelineBarrier after renderpass execution already finished?

像上面那些记录的障碍告诉你的 GPU 是这样的:

  • 在当前队列中,等待具有 FRAGMENT_SHADER 阶段的所有先前命令完成其 FRAGMENT_SHADER 阶段,然后再继续其 TRANSFER 阶段中的后续命令。

这也意味着:

  • 如果队列中没有之前的命令,则屏障的要求已经满足,可以立即继续执行后续命令。
  • 如果队列中有可能不会经过 FRAGMENT_SHADER 个阶段的命令,我们不会等待它们。
  • 障碍适用于曾经提交给队列的每个命令。 (但大多数命令将不再“运行中”,而是已经被删除,因为它们已完成执行。)屏障的 src 依赖性 never 指的是某些东西以后可能会提交,只针对之前提交过的东西。

如果您对这些事情有困难,您可能想看看 Introduction to Vulkan lecture which covers such synchronization topics from 22:28 以后的内容。