1
votes

I have a very simple setup - in fact one of the earlier stages of vkguide.dev. So a single render pass with a single subpass. Those have one color and one depth attachment.

The color AttachmentDescription has .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED and .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR. In its SubPassDescription, it has .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.

The depth AttachmentDescription has .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED and .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL. In its SubPassDescription, it has .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL.

I'm trying to understand the subpass dependencies, so I don't want to rely on the implicit ones the spec provides but provide my own, minimal ones.

When I provide "zeroed out" subpass dependencies, I get a the following error with sync validation turned on:

Validation Error: [ SYNC-HAZARD-WRITE_AFTER_WRITE ] Object 0: handle = 0x83d4ee000000000b, type = VK_OBJECT_TYPE_RENDER_PASS; | MessageID = 0xfdf9f5e1 | vkCmdBeginRenderPass: Hazard WRITE_AFTER_WRITE vs. layout transition in subpass 0 for attachment 1 aspect depth during load with loadOp VK_ATTACHMENT_LOAD_OP_CLEAR.

So he's complaining about the depth attachment (attachment 1). And I can fix this with the following set of explicit subpass dependencies:

constexpr VkSubpassDependency in_dependency{
    .srcSubpass = VK_SUBPASS_EXTERNAL,
    .dstSubpass = 0,
    .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    .dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
    .srcAccessMask = 0,
    .dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
};

constexpr VkSubpassDependency out_dependency = {
    .srcSubpass = 0,
    .dstSubpass = VK_SUBPASS_EXTERNAL,
    .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    .srcAccessMask = 0,
    .dstAccessMask = 0,
    .dependencyFlags = 0
};

The second of course is only there to not use the second implicit one and does nothing. The first one is an explicit dependency between things before the renderpass and the first/only subpass. But I don't really understand - a couple of questions:

  • does a srcAccessMask = 0 really define a real dependency? it's empty after all, or are things different with a VK_SUBPASS_EXTERNAL?
  • Why do I only need a dependency on the depth- and not on the color attachment?

I made the image below and am aware that color attachment gets loaded and stored in the same pipeline stage, and that the depth attachment does now. However I still don't understand why that eliminates the need for a dependency. That pipeline stage could still overlap between two renderpasses right?

pipeline

1

1 Answers

1
votes

does a srcAccessMask = 0 really define a real dependency? it's empty after all, or are things different with a VK_SUBPASS_EXTERNAL?

Yes it does. It is called an execution dependency (as opposed to memory dependency). It becomes relevant in dependency chaining.

Consider this code:

vkCmdPipelineBarrier(
    srcStage = WHATEVER_STAGE, srcAccess = MEMORY_WRITE,
    dstStage = COOL_STAGE, dstStage = 0
);
vkCmdPipelineBarrier(
    srcStage = COOL_STAGE, srcAccess = 0,
    dstStage = WHATEVER_ELSE_STAGE, dstAccess = MEMORY_READ
);

It is equivalent to a single dependency:

vkCmdPipelineBarrier(
    srcStage = WHATEVER_STAGE, srcAccess = MEMORY_WRITE,
    dstStage = WHATEVER_ELSE_STAGE, dstAccess = MEMORY_READ
);

Why do I only need a dependency on the depth- and not on the color attachment?

The validation might be implemented imperfectly. Or likely the color attachment is treated differently in your code (the color images are presented, while the depth is not). Which either sneaks the dependency there, or makes it less trivial for the validator to catch.