Semaphore synchronization

Let’s say we have a semaphore that signals, thus signaling something. Waiting stages: VK_PIPELINE_STAGE_VERTEX_SHADER_BIT. Can I, in theory, create a pipeline barrier and specify as srcStage the value from waiting stages (and the commands before the barrier do not have this stage) and be sure that synchronization will be successful? Simply put: can I use a semaphore that is expected at a certain stage for synchronization if that stage is not in the commands?

OK, so this pipeline barrier is somewhere in the batch of work that is waiting for the semaphore.

What does “successful” mean? The two sets of dependencies will form an execution dependency chain, as specified in the standard, because the source scope of the second dependency and the destination scope of the first dependency are not an empty set.

1 Like

Perhaps “successful” is not the most specific definition. That’s what I wanted to say: will this semaphore be expected on the first submit and on subsequent submits?
And, if you don’t mind, give a link to the part of the specification you described in the last reply

Yes, at the minimum by the rules of execution dependency chaining.

Try to think of pipeline as an actual pipeline. The pipeline (and its stages) do not cease to exist just because nothing currently flows through it.

If you specify something as srcStage then all pending ops are guaranteed to reach at least up to that stage (before the layout transition, and the second synchronization scope are allowed to proceed). If the semaphore wait was proced in srcStage or earlier, then it must have been completed.

1 Like

Ok, then if you leave the same srcStages but change waitStages to topOfPipe, the semaphore will be expected, but if, for example, to fragmentShader, it will not.
Right?

I am not familiar with the concept of a semaphore being “expected”.

If pWaitDstStageMask is STAGE_TOP_OF_PIPE then the semaphore blocks everything in the batch regardless of anything else.

If pWaitDstStageMask is X, then the operations in the batch are allowed to proceed up to and excluding X (but no further).

If srcStage of a barrier is Y, then all operations finish at least to Y (inclusive), before layout transition and dst side is allowed to proceed.

Either you can consider the semaphore wait op as any other op, and it either is or isn’t covered by the barrier’s srcStage by normal rules. Or you can invoke the concept of Dependency Chaining. I.e. if the dst scope of one sync primitive overlaps with the src scope of following synchronization primitive, then an “execution dependency chain” is formed behaving as if there was a single synchronization primitive composed of src of the first original sync primitive and dst of the second one.

Teh specc on semaphore wait operation:

In the case of vkQueueSubmit, the second synchronization scope is limited to operations on the pipeline stages determined by the destination stage mask specified by the corresponding element of pWaitDstStageMask. Also, in the case of vkQueueSubmit, the second synchronization scope additionally includes all commands that occur later in submission order.

on pipeline barriers:

If vkCmdPipelineBarrier was recorded outside a render pass instance, the first synchronization scope includes all commands that occur earlier in submission order. […]
the first synchronization scope is limited to operations on the pipeline stages determined by the source stage mask specified by srcStageMask.

on chaining:

For each consecutive pair of execution dependencies, a chain exists if the intersection of Scope2nd in the first dependency and Scope1st in the second dependency is not an empty set.

1 Like

Okay. So for the sake of understanding, we can think of waiting for a semaphore as an operation that is executed on waitStages?

Semaphores are just a dependency operation. They are not “executed” on any stages.

1 Like

With some caveats.

Firstly, it does not happen on pWaitDstStageMask. It happens at the latest on pWaitDstStageMask (i.e. possibly at any point earlier).

Second caveat with this interpretation is again it does not happen exactly on pWaitDstStageMask. It happens before any of the operations in the batch going through pWaitDstStageMask stage, which the semaphore is supposed to block.

Nevertheless the known quantity here is the Semaphore Wait Operation is guaranteed to be finished at some point before the pWaitDstStageMask stage.

Therefore for the purpose of a following Pipeline Barrier and its srcStageMask we can reason whether it is covered by it or not. If srcStageMask == S and Semaphore Wait Operation happens at some point before S (because pWaitDstStageMask == S), then we can say it is covered by the Pipeline Barrier.


If you are not comfortable with this, you can invoke the Execution Dependency Chain concept to explain this, which can be a headache of its own if you are not familiar with it.

Above I quoted from the spec the scopes of Semaphore and Pipeline Barrier formally. But basically:

  • the Semaphore says its Second Scope is whatever operation in the submit, limited to pWaitDstStageMask stages or later (let’s assume we set this parameter to value S).
  • the Pipeline Barrier says its First Scope is whatever operation before it in the submit, limited to srcStageMask stages or earlier (let’s assume we set this parameter to value S).

Execution Dependency Chain between the Semaphore and the Barrier (or generally between any sequence of two sync primitives) is formed if there is an overlap between these two Scopes. How you determine whether that is so is, you mentally try to merge the two sentences together and then determine if it is satisfiable. I.e. merging the two above would yield:

“Whatever operation from the start of the batch and before the barrier, limited to exactly stage S.”

That is a satisfiable predicate (i.e. can be satisfied under some hypothetical situation), therefore an Execution Dependency Chain is formed, guaranteeing First Scope of the Semaphore (the signal and whatever that guards) happens-before the Second Scope of the Barrier (i.e. its “dst” half and whatever that is trying to block).

On the contrary example, if we set pWaitDstStageMask = STAGE_BOTTOM_OF_PIPE for the Semaphore, and srcStageMask = STAGE_TOP_OF_PIPE in the Barrier, then that would yield:

“Whatever operation from the start of the batch and before the barrier, limited to STAGE_BOTTOM_OF_PIPE or earlier AND STAGE_TOP_OF_PIPE or later stage.”

That is an unsatisfiable predicate because the Venn diagram of these two stage restrictions do not intersect (for any and all hypothetical scenarios). Therefore a Dependency Chain is not formed, and therefore no ordering is established between the Semaphore signal (and the previous associated work with it) and whatever the Barrier tries to guard.

2 Likes

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.