Search code examples
pipelinevulkanbarrier

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


What stages can be set for srcStageMask/dstStageMask when submitting a vkCmdPipelineBarrier out of a renderpass, because in such case there is no subpass bind point to graphics pipeline?

The same question for when submitting vkCmdPipelineBarrier in subpass that has a bind point to a compute pipeline which I guess doesn't have stages like VK_PIPELINE_STAGE_VERTEX_SHADER_BIT and maybe many more.

Thanks

Edit

First, thanks to @Nicol Bolas comment, a compute shader can not be dispatched in middle of subpass.

And I would like to clarify my question:

Say I have an image that after a renderpass will have the layout of VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.

After the renderpass, I want to update the image with new data and wish to change its layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.

Thus, after recording vkCmdEndRenderPass I record a vkCmdPipelineBarrier command as follows:

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);

This ensures transition waits as long as previous command within renderpass still didn't cross the fragment shader stage.

But what if vulkan executes vkCmdPipelineBarrier after renderpass execution already finished? now there is no bound pipeline , no stages - does it means the barrier will go into an endless wait until a new renderpass will begin and a fragment shader stage will happen?


Solution

  • If I got everything right, then what you want to synchronize is the following:
    You would like to ensure that the image is not overwritten with new data before a preceding renderpass has finished reading the image.

    To achieve this, you have set up barriers which synchronize

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

    While these synchronization parameters ensure correctness, they are actually a bit more than necessary. The srcAccessMask is used for memory that needs to be "made available", which means ~transfer into L2 memory, so that it can be accessed afterwards.

    This is the part which is unnecessary in your barrier, because the memory already is available (in L2 memory), otherwise it could not have been read properly.

    I.e. the optimal barrier would be as follows:

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

    Now to the question about

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

    What a recorded barrier like those above tell your GPU is the following:

    • Within the current queue, wait for all preceding commands which have a FRAGMENT_SHADER stage to have completed their FRAGMENT_SHADER stages before continuing with subsequent commands in their TRANSFER stages.

    That also means:

    • If there are no previous commands in the queue, the requirement of the barrier is already fulfilled and execution of further commands can continue immediately.
    • If there are commands in the queue that do not potentially go through FRAGMENT_SHADER stages, we don't wait for them.
    • The barrier applies to every command that has ever been submitted to the queue. (But most commands will no longer be "in flight" but will already have been removed because they have completed execution.) The src dependencies of a barrier never refer to something that might be submitted in the future, only to things that have been submitted previously.

    If you have difficulties with these things, you might want to have a look at the Introduction to Vulkan lecture which covers such synchronization topics from 22:28 onwards.