Search code examples
synchronizationvulkanmemory-barriers

Successive compute kernels in vulkan


I have three compute kernels that have to run in succession, synchronized so that the previous kernel finishes before the next kernel starts.

This is because a previous kernel writes a buffer that is used by the next kernel.

This may be a mistake, but what I have now:

  • 1 device
  • 1 queue
  • 1 command buffer
  • 3 compute pipelines, one for each kernel

I tried adding VkMemoryBarrier and VkBufferMemoryBarrier, but I don't think I have synchronized them, because they were placed on a pipeline, and I think not between pipelines? I added them with vkCmdPipelineBarrier

What would be a good way to make sure three compute kernels run in succession, with the caches flushed between them?

UPDATE

This is how I create a memory barrier:

static void add_memory_barrier(VkDeviceMemory mem, VkCommandBuffer cmdBuf, VkDeviceSize sz)
{
        const VkMemoryBarrier b =
        {
                VK_STRUCTURE_TYPE_MEMORY_BARRIER,
                0,
                VK_ACCESS_SHADER_WRITE_BIT,
                VK_ACCESS_SHADER_READ_BIT,
        };
        vkCmdPipelineBarrier
        (
                cmdBuf,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
                0,              // dependency flags
                1,              // num memory barriers
                &b,
                0,              // num buffer memory barriers
                0,
                0,              // num image memory barriers
                0
        );
}

Solution

  • https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples https://themaister.net/blog/2019/08/14/yet-another-blog-explaining-vulkan-synchronization/ https://www.khronos.org/blog/understanding-vulkan-synchronization

    I think that the first example in the first link pretty much answers your question. Your approach is probably working as long as you specify the correct Stage and Access masks, but you didn't say which ones you are using.

    Barriers also don't have the notion of being "on a pipeline" or "between pipelines". A pipeline bind just says what pipeline should be in effect for the next dispatch and doesn't interact with a barrier.

    So if you put in a command buffer:

    Bind A, Dispatch A, Barrier, Bind B, Dispatch B

    this should be the same as:

    Bind A, Dispatch A, Bind B, Barrier, Dispatch B

    The bind of B really doesn't take effect until the dispatch of B and that won't happen until the barrier is satisfied.