Understanding subpass/memory dependencies

I’m having a hard time understanding memory and subpass dependencies. I will try to explain how I understand it to this point and I would appreciate if you would correct me when I got something wrong.

In my understanding, the pipeline can run through all its stages multiple times between two dependencies. Two draw calls, for example, require the pipeline to run two times; from vertex input to color attachment output. Now lets say we got two subpasses: the first one drawing to a set of color attachments, the second one reading from them and drawing to another set of color attachments.
The first subpass has a dependency to “VK_SUBPASS_EXTERNAL” with srcStageMask being “VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT” to ensure that the subpass is executed only when the previous pipeline invocation has been completed and a new one has been started. dstStageMask is “VK_PIPELINE_STAGE_VERTEX_INPUT_BIT”, to indicate that the subpass is starting execution at this stage.
The second subpass has srcStageMask being “VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT” to ensure that writes to the color attachments have been completed, before starting this subpass. Now, this is the point where my understanding starts to show its flaws: I would now assume that dstStageMask would be “VK_PIPELINE_STAGE_VERTEX_INPUT_BIT” again, indicating that the second subpass starts at a new invocation of the pipeline, drawing new stuff. But the specification says this is invalid, because dstStageMask must be later than srcStageMask to ensure no circular dependency is happening. This kind of destorys my notion that the pipeline runs through its stages multiple times.

I probably got something seriously wrong here, because this doesn’t make any sense to me.

if you need the output from the first render in a non-fragment shader or sampled arbitrarily (like shadow maps,blurs) in a subsequent render then you cannot have the two renders in the same renderpass.

If you need the output of the first in the fragment shader of the second and only the output on the same fragments (as an input attachment) then you can combine the renders into a single renderpass.

EDIT: The specification doesn’t say that dstStageMask must be later than srcStageMask, but srcSubpass must be later than dstSubpass. Need to read the spec more carefully.
Now a few things became clear.

Ok, I am game…

In my understanding, the pipeline can run through all its stages multiple times between two dependencies.

That’s probably true, but I find it a bit confusing, so let me offer alternative description from the point of view of the barrier (subpass dependency is for most intents and purposes barrier too). There are two sets of commands: recorded before the barrier and recorded after the barrier. Any (action) command needs N passes through !a! pipeline. Their execution can overlap and be reordered freely, except for how the two sets treat each other governed by the barrier’s parameters.

from vertex input to color attachment output

Personally, I think (other than TOP and BOTTOM) that it is dangerous to assume some order of the pipeline stages. Especially with the BY_REGION dependency. I think, you do not even need to be aware of the order most of the time.

The first subpass has a dependency to “VK_SUBPASS_EXTERNAL” with srcStageMask being “VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT” to ensure that the subpass is executed only when the previous pipeline invocation has been completed and a new one has been started.

You mean “from VK_SUBPASS_EXTERNAL to itself”. I think ALL_COMMANDS is more appropriate enum for that use. Exactly because of the error you made. src=TOP means exactly opposite of what you say (Meaning TOP stage execution of commands in the first set must be finished before your STAGE_VERTEX_INPUT of second set. But TOP is always finished, so it does not block. And for dstStage the logic would be opposite.)

dstStageMask is “VK_PIPELINE_STAGE_VERTEX_INPUT_BIT”, to indicate that the subpass is starting execution at this stage.

Not quite. It means earlier stages than STAGE_VERTEX_INPUT (of the second set) may start earlier than srcStage of the first set of commands is finished.

I would now assume that dstStageMask would be “VK_PIPELINE_STAGE_VERTEX_INPUT_BIT” again, indicating that the second subpass starts at a new invocation of the pipeline, drawing new stuff. But the specification says this is invalid, because dstStageMask must be later than srcStageMask to ensure no circular dependency is happening

Depends on what you do after the second subpass. If you do nothing and just wait to be presented, then dependency to VK_SUBPASS_EXTERNAL and STAGE_BOTTOM(non-blocking) is appropriate (rest is done with a semaphore). “earlier” and “later” stage does not even enter this problem — the spec just says you should not circle your DAG of subpasses (which is different problem. BTW, that is what DAG means.).

this doesn’t make any sense to me.

That’s a normal stage. (har har)