How could a dependency be placed between a stage and the stage itself?

In the 7.4.2. Semaphore Waiting of specification:
https://www.khronos.org/registry/vulkan/specs/1.2-khr-extensions/html/vkspec.html#synchronization-semaphores

Note

A common scenario for using pWaitDstStageMask with values other than VK_PIPELINE_STAGE_ALL_COMMANDS_BIT is when synchronizing a window system presentation operation against subsequent command buffers which render the next frame. In this case, a presentation image must not be overwritten until the presentation operation completes, but other pipeline stages can execute without waiting. A mask of VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT prevents subsequent color attachment writes from executing until the semaphore signals. Some implementations may be able to execute transfer operations and/or vertex processing work before the semaphore is signaled.

If an image layout transition needs to be performed on a presentable image before it is used in a framebuffer, that can be performed as the first operation submitted to the queue after acquiring the image, and should not prevent other work from overlapping with the presentation operation. For example, a VkImageMemoryBarrier could use:

  • srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  • srcAccessMask = 0
  • dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  • dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
  • oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
  • newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL

Alternatively, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image’s contents need not be preserved.

This barrier accomplishes a dependency chain between previous presentation operations and subsequent color attachment output operations, with the layout transition performed in between, and does not introduce a dependency between previous work and any vertex processing stages. More precisely, the semaphore signals after the presentation operation completes, the semaphore wait stalls the VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage, and there is a dependency from that same stage to itself with the layout transition performed in between.

Because it is not a dependency between stages. It is a pipeline, not a finite stage machine, so there are no such things as dependencies between stages.

What there is are dependencies between synchronization scopes. The above code says all previous queue operations will reach VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, before any subsequent queue operation will reach VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT in its execution.

Let’s say first,presentation engine signals imageAvaliableSemaphore ,then VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT is allowed to run,how does the depen in the above guarantee the layout transtion happens after imageAvaliableSemaphore has been signaled and before VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stage starts?

if this mentioned VkImageMemoryBarrier is the first command within a renderpass,there is no other VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stages included in this VkImageMemoryBarrier 's first synchronization scope except those in last frame,which I think is irrelevent.

One explanation I can think of is that:
First dependecy (via semaphore submitted with vkQueueSubmit):
srcStage A = presentationEngine finish reading frame buffer image
dstStage B = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
Second dependecy:
srcStage B = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
dstStage B= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

And because we have a dependency chain,then the dstStage of first dependency and the srcStage of second dependency are One explanation I can think of is that:
First dependecy (via semaphore submitted with vkQueueSubmit):
srcStage A = presentationEngine finish reading frame buffer image
dstStage B = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
Second dependecy(via vkImageBarrier or subpassDepen):
srcStage B = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
dstStage B= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

And because we have a dependency chain,then the dstStage of first dependency and the srcStage of second dependency are cancelled,what I effctive get is the only one depen like this:
srcStage A = presentationEngine finish reading frame buffer image
dstStage B = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

The formation of a single execution dependency from an execution dependency chain can be described by substituting the following in the description of execution dependencies:

  • Let S be a set of synchronization commands that generate an execution dependency chain.
  • Let AS be the first synchronization scope of the first command in S.
  • Let BS be the second synchronization scope of the last command in S.

Again, it is a pipeline, not a FSM. Stages are not “run” or “start”. Stages just exist, and commands are run through them. Hence the name “pipeline”.

pWaitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT says the semaphore will be waited on no later than that stage.

srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT says all previous operations in the queue (including the semaphore wait) reach at least the COLOR_ATTACHMENT_OUTPUT stage of their respective execution.

Well it is irrelevant. You could think of the semaphore wait to have the stage included in pWaitDstStageMask. Or otherwisely, in Vulkan there is defined the concept of execution dependency chain. If there are two sync primitives, and the stages match like this, then dependency chain is formed.

So my explanation using dependency chain is correct,right?
I mean,If you merely see this dependency:

VkImageMemoryBarrier could use:

  • srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  • srcAccessMask = 0
  • dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  • dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
  • oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
  • newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL

It states: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT(srcStageMask) have to be run through by commands first then VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT(dstStageMask) can be run through by commands.For me,it’s like"You have to finish eating all your food before you can start to eat your food.",which is contradictory.So this depen has to be understood as part of a dependency chain,right?

No, it’s “you have to finish eating all the food you’ve been given before you can start eating your next meal”. “food” here corresponding to the “COLOR_ATTACHMENT” stage.

And even that analogy leaves stuff out.

1 Like

Yea, it is fine with me to invoke the dependency chaining here for the semaphore+barrier interaction.

Your FSM-like mental model will only bring you grief though. It causes such mental artifacts as problems with internalizing the meaning of the above dependency. If you start to think of pipeline as being pipeline, then things start to make more sense.

The above dependency makes perfect sense then. It states: all previously recorded queue operations must reach at least COLOR_ATTACHMENT stage in their respective executions, before any of the subsequent queue operations reach COLOR_ATTACHMENT stage in their respective executions. I.e. something like " none of these people are allowed to eat breakfast, until all these other people already had breakfast".

Such dependency does not need chaining to make sense. E.g. if you have two render pass instances that draw stuff to a common framebuffer, then you would have to put src=COLOR_ATTACHMENT, dst=COLOR_ATTACHMENT dependency between them, so there would be no memory hazard on that framebuffer.

Yes,

I first adopted this mentality,but all previously recorded queue operations only includes those operations used to render former frames, then I can’t figure out how former frames’ COLOR_ATTACHMENT stages’ completion could relate to current frame’s use of swap chain image.
For example,frame0 has gone through COLOR_ATTACHMENT stage,and that only means the swap chain image used by frame0 is ready to be presented on a screen,but not that presentation engine has finish reading from the swap chain image used by frame0,and all those has nothing to do with frame1.

And you mentioned that there might be two frames(say frame0 and frame1,and frame0 submitted to queue first) that use the same swap chain image,but in that case,the dependency seems to be redundant,cuz the signal of imageAvaliableSemaphore passed into vkQueueSubmit() to render frame1 gareentees not only the completion of COLOR_ATTACHMENT stage of frame0 but also the presentation engine’s reading of commonly-used swap chain image

I was answering the part why srcStage hypothetically can equal dstStage in a barrier, which seems to have confuse you. WSI is its own brainfuck, so let’s not go there right now. I was not saying anything about a swapchain; framebuffer can be a non-swapchain image (and I mean, you can draw to a swapchain image multiple times too between presents).

Anyway, AIS, dependency chaining is sufficient to explain the semaphore + barrier interaction. Otherwisely you could think of the semaphore wait as a queue operation with pipeline pWaitDstStage ⇒ BOTTOM_OF_PIPE. The result is the same.

Indeed it may look that way at the first sight.

But you have two accessors there. You have the presentation engine read, and then you have the layout transition (which is a R/W operation). How do you make sure those two do not form a memory hazard?

Layout transition is a queue operation that is defined to happen somewhere non-specific between source scope and destination scope of the dependency it is part of. If srcStageMask was TOP_OF_PIPE, then semaphore wait with pWaitDstStage = COLOR_ATTACHMENT would not cover that layout transition, and therefore presentation read and layout transition write could be happening at the same time.

1 Like

Thanks for you patience,krOoze.And I found a great post here also pertaining to my question:

And another thing I want to point out is(maybe this will help you to teach others) :the FSM mentality is a reluctant choice(because I have no idea of dependency chain then so the normal way of interpreting barrier didn’t have any meaning(like why care about stages of former frames?)even though it’s definitely legitimate and also the spec is confusing here:

and there is a dependency from that same stage to itself with the layout transition performed in between.