我可以在命令缓冲区中多次记录 vkCmdPipelineBarrier 吗?

Can I record vkCmdPipelineBarrier multiple times in a command buffer?

我有一个 vkImage 来自 vkSwapchain。我的目标很简单,就是在这个图像中渲染一个三角形。所以我创建了一个命令缓冲区并记录为以下命令。

  1. vkBeginCommandBuffer
  2. vkCmdPipelineBarrier(从 LAYOUT_UNDEFINEDCOLOR_ATTACHMENT_OPTIMAL
  3. vkCmdBeginRenderPass
  4. 画出我的三角形。
  5. vkCmdEndRenderPass
  6. vkCmdPipelineBarrier(从COLOR_ATTACHMENT_OPTIMALPRESENT_SRC
  7. vkEndCommandBuffer

最后我调用 vkQueueSubmit 在屏幕上得到一个三角形。但是当 second vkCmdPipelineBarrier 执行时,验证层说:

VUID-VkImageMemoryBarrier-oldLayout-01197: For image 0x4 you cannot transition the layout of aspect=1 level=0 layer=0 from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when the previous known layout is VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout: Submitted command buffer expects image 0x4 (subresource: aspectMask 0x1 array layer 0, mip level 0) to be in layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL--instead, current layout is VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

但我敢肯定那时的图像布局会是 COLOR_ATTACHMENT_OPTIMAL。我不知道为什么验证层向我抱怨。

我搜索了 API 文档,但找不到 vkCmdPipelineBarrier 的任何限制。他们说这个命令执行队列所有权转移(如果需要)和布局转换。

下面是我的代码。

//////////////////////////////////////////////////////
// First layout transition
//////////////////////////////////////////////////////
VkImageMemoryBarrier vkGraphicsImageMemoryBarrier
{
    VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    nullptr,
    0,
    VkAccessFlagBits::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED,
    VkImageLayout::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    VK_QUEUE_FAMILY_IGNORED,
    VK_QUEUE_FAMILY_IGNORED,
    this->sSwapchain.vulkanImageList()[nImageIndex],
    VkImageSubresourceRange
    {
        VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT,
        0,
        VK_REMAINING_MIP_LEVELS,
        0,
        VK_REMAINING_ARRAY_LAYERS
    }
};

vkCmdPipelineBarrier(
    this->sGraphicsCommandBufferList[nImageIndex],
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    0,
    0, nullptr,
    0, nullptr,
    1, &vkGraphicsImageMemoryBarrier);

//
//  Draws a triangle.
//

//////////////////////////////////////////////////////
// Second layout transition and ownership transfer
//////////////////////////////////////////////////////
VkImageMemoryBarrier vkGraphicsImageMemoryBarrier
{
    VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    nullptr,
    VkAccessFlagBits::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    0,
    VkImageLayout::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    VkImageLayout::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    this->nGraphicsFamily,
    this->nPresentFamily,
    this->sSwapchain.vulkanImageList()[nImageIndex],
    VkImageSubresourceRange
    {
        VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT,
        0,
        VK_REMAINING_MIP_LEVELS,
        0,
        VK_REMAINING_ARRAY_LAYERS
    }
};
VkImageMemoryBarrier vkPresentImageMemoryBarrier
{
    VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    nullptr,
    0,
    0,
    VkImageLayout::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    VkImageLayout::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    this->nGraphicsFamily,
    this->nPresentFamily,
    this->sSwapchain.vulkanImageList()[nImageIndex],
    VkImageSubresourceRange
    {
        VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT,
        0,
        VK_REMAINING_MIP_LEVELS,
        0,
        VK_REMAINING_ARRAY_LAYERS
    }
};

//
//  Below call produces the above validation message.
//
vkCmdPipelineBarrier(
    this->sGraphicsCommandBufferList[nImageIndex],
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    0,
    0, nullptr,
    0, nullptr,
    1, &vkGraphicsImageMemoryBarrier);
vkCmdPipelineBarrier(
    this->sPresentCommandBufferList[nImageIndex],
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    VkPipelineStageFlagBits::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    0,
    0, nullptr,
    0, nullptr,
    1, &vkPresentImageMemoryBarrier);

尽管有验证错误消息,我还是得到了一个三角形渲染。这是验证层错误吗?

如有任何帮助,我们将不胜感激。

您可以在命令缓冲区中记录多少个管道障碍(内存限制除外)

然而,不需要那个特定的屏障,因为相同的屏障可以由 renderpass 隐式完成。验证抱怨图像布局已经存在这一事实意味着您已经以这种方式进行了设置。创建renderpass时检查附件的finalLayout。