Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subpass dependencies for a single subpass. How to?

Tags:

vulkan

So I have a render pass with a single subpass that draws directly to a framebuffer. The specification doesn't force me to use dependencies - if I omit them, the implementation inserts them implicitly (though I don't understand why it uses srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT for the first subpass - this stage means the very beginning, i.e. don't wait for anything).

But as usual with the Vulkan - better to be explicit. And here is the confusion - multiple sources use subpasses differently.

  1. Sdk's cube example does not use them at all.

  2. Vulkan-tutorial uses only one:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = 0;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    Why srcAccessMask is zero here?

  3. API without secrets uses two:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    dependency.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    and

    dependency.srcSubpass = 0;
    dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    

    It's not very clear why srcStageMaskis VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT in the first subpass - isn't this stage should be used for execution dependencies, but here we need a memory dependency? The same question about why dstStageMask is VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT in the second subpass?

  4. Khronos synchronization examples uses one:

    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.srcAccessMask = 0;
    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    

    Why srcAccessMask is 0?

  5. And here's my attempt with two dependencies:

        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
        dependency.dstSubpass = 0;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // need to wait until
    presentation is finished reading the image
        dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // we are writing to
    the image in this stage
        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    
    and
    
        dependency.srcSubpass = 0;
        dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // we are writing to
    the image in this stage
        dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // presentation reads
    image in this stage (is it?)
        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    

All this is very confusing. As you can see multiple competent sources have a different vision. Which one to use? How to understand these dependencies?

like image 797
nikitablack Avatar asked Oct 26 '18 07:10

nikitablack


People also ask

What are subpass dependencies?

Subpass dependencies are basically syntactic sugar for pipeline barriers targeting attachments during a render pass. Internal dependencies (those with non-external but distinct subpass indices) are used to ensure order between subpasses.

What is a Vulkan Subpass?

The use of a render pass in a command buffer is a render pass instance.” Page 4 4 7.0 Render Pass Vulkan® 1.1.74 - A Specification (with KHR extensions) “A subpass represents a phase of rendering that reads and writes a subset of the attachments in a render pass.

What is a Vulkan attachment?

Framebuffers represent a collection of memory attachments that are used by a render pass instance. Examples of these memory attachments include the color image buffers and depth buffer that we created in previous samples.


1 Answers

Oh dear, this is a topic that is not that well understood by most people. A lot of misinformation was assumed and proliferated. The proper place for canonical examples is the wikipage in the github repo.

The relevant section about swapchain images acquire/present can be found here.

  1. it's an old example from before a lot of the synchronization specifics were properly nailed down.

  2. The purpose there is to synchronize the semaphore use to wait on the result of vkAcquireNextImage with rendering. This is a write-after-read hazard and the semaphore will include memory visibility synchronization. So srcAccessMask is no necessary.

  3. Again the barrier is meant to sync against the semaphore. When submitting a command buffer to a queue you can set which stages wait on which semaphores. In this case they use the bottom of pipe stage instead of the VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

  4. same answer as 2, the only difference is with the dstAccessMask

  5. The wiki page I linked above uses the following:

    /* Only need a dependency coming in to ensure that the first
       layout transition happens at the right time.
       Second external dependency is implied by having a different
       finalLayout and subpass layout. */
    VkSubpassDependency dependency = {
        .srcSubpass = VK_SUBPASS_EXTERNAL,
        .dstSubpass = 0,
        // .srcStageMask needs to be a part of pWaitDstStageMask in the WSI semaphore.
        .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
        .srcAccessMask = 0,
        .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
        .dependencyFlags = 0};
    
    /* Normally, we would need an external dependency at the end as well since we are changing layout in finalLayout,
       but since we are signalling a semaphore, we can rely on Vulkan's default behavior,
       which injects an external dependency here with
       dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
       dstAccessMask = 0. */
    

    You mixed up the subpass indices for the second barrier. Though as mentioned in the comments there is already an implicit barrier at the end of the renderpass which in turn syncs against the semaphore or fence you use to sync against the present. So there is no need fo an explicit dependency.

like image 177
ratchet freak Avatar answered Sep 28 '22 00:09

ratchet freak