Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite dependency chapter #1833

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 132 additions & 64 deletions chapters/synchronization.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,67 +53,133 @@ _memory dependencies_ between two sets of operations defined by the
command's two _synchronization scopes_.

[[synchronization-dependencies-scopes]]
The synchronization scopes define which other operations a synchronization
command is able to create execution dependencies with.
Any type of operation that is not in a synchronization command's
A synchronization scope is a set of selection criteria for operations.
Tobski marked this conversation as resolved.
Show resolved Hide resolved
A synchronization command has a first synchronization scope and a second
synchronization scope for the purpose od declaring which kinds of operations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"od" -> "of"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry too much about typos for now. I will self-review stuff if and when we dedraft this and I will render it and run spellcheck.

are subject to the dependency introduced by the command.
Any type of operation that is not selected by the synchronization command's
synchronization scopes will not be included in the resulting dependency.
Comment on lines +58 to 61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
synchronization scope for the purpose od declaring which kinds of operations
are subject to the dependency introduced by the command.
Any type of operation that is not selected by the synchronization command's
synchronization scopes will not be included in the resulting dependency.
synchronization scope identifying two sets of operations that will be synchronized
by the command.
Operations that aren't included in these scopes will not be affected by the
command.

I'd rather avoid saying "dependency" in a definition until after the concept has been introduced below (yes I know the text already says it, but we're improving things here 😬)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependencies are introduced in the first paragraph of the chapter. For that matter it is the name of the chapter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By chapter I assume you mean section? And yes, they are, but the concepts themselves are being built up to be explained - they haven't been introduced at this point in the section other than by name. I think this suggestion pairs with the change here or it doesn't entirely make sense.


[NOTE]
.Note
====
For example, for many synchronization commands, the synchronization scopes
can: be limited to just operations executing in specific
can: be limited to just operations executing in only specific
<<synchronization-pipeline-stages,pipeline stages>>, which allows other
pipeline stages to be excluded from a dependency.
Other scoping options are possible, depending on the particular command.
But other scope to other kinds of operations is possible depending on the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 70, reword.

particular command, such as the <<synchronization-fences-signaling,
fence signal operation>>.
====

[[synchronization-dependencies-execution]]
An _execution dependency_ is a guarantee that for two sets of operations,
the first set must: _happen-before_ the second set.
If an operation happens-before another operation, then the first operation
must: complete before the second operation is initiated.
An _execution dependency_ is an implementation's guarantee that for two sets
of operations, the first set must: _happen-before_ the second set.
If an operation _happens-before_ another operation, it means the first
operation must: complete before the second operation is initiated.
More precisely:
Comment on lines +76 to 80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure adding "an implementation's" here has the intended effect. My gut says maybe we need to work harder to separate the definition from who guarantees it.

Maybe:

Suggested change
An _execution dependency_ is an implementation's guarantee that for two sets
of operations, the first set must: _happen-before_ the second set.
If an operation _happens-before_ another operation, it means the first
operation must: complete before the second operation is initiated.
More precisely:
An _execution dependency_ defines a relationship between two sets
of operations, such that one set happens-before the other.
Applications can: express execution dependencies via synchronization
commands that require: an implementation to uphold this guarantee,
as defined below:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"happens-before" => "is executed" ? "happens" seems ambiguous.

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stonesthrow I think this is basically first definition of what "happens-before" means, which has very formal meaning. But I think it is otherwisely unfortunately specified only in the extension.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, reading it back it seems this is what we were trying to use as a sort of bootstrapped definition of happens-before, and I don't think it does a good job in light of the memory model definition. "Happens before" is an industry term though (it's on wikipedia!) so I'm kind of inclined to leave it in pending a memory model rewrite that properly introduces the idea later...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, if its a understood term. I do understand. But its vague in that "happens" by some unknown entity. Verses this entity does such and such before the next step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stonesthrow It's a term defined in the memory_model extension, but it is used througout the specification.


* Let *A* and *B* be separate sets of operations.
* Let *Ops* be a set of all submitted operations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible issue here is that *S* itself is a set of operations, so would be included in *Ops*. I'm not 100% sure what the ramifications of that might be at the moment...

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tobski I try to make the scopes do all the work, so if they do not want to include S they just need to say so.

I have not had time to wholistically review stuff yet (hence draft PR), but typically the scope is writen like "all operations recorded before S that operate in stage P", therefore S should never be part of the scope.

I think it might catch other synchronization operations. Which might be a defect from before I think. Should be cleared all the same though. Going to keep this in mind when I update this PR...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea that is all in line with my thinking, so that's fine, just something to be aware of.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible alternative terms: A is the "prerequisite" operation(s) and B is the "dependent" operation(s).
Synchronization requires the prerequisite to execute before the dependent executes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stonesthrow I don't need A and B here at all, because scopes are generally already defined as downselecting to previous or subsequent operations.

* Let *S* be a synchronization command.
* Let *A~S~* and *B~S~* be the synchronization scopes of *S*.
* Let *A'* be the intersection of sets *A* and *A~S~*.
* Let *B'* be the intersection of sets *B* and *B~S~*.
* Submitting *A*, *S* and *B* for execution, in that order, will result in
execution dependency *E* between *A'* and *B'*.
* Execution dependency *E* guarantees that *A'* happens-before *B'*.
* Let *Scope~src~* be the first synchronization scope of *S*.
* Let *Scope~dst~* be the second synchronization scope of *S*.
* Let *Ops~src~* be the subset of operations in *Ops* selected by scope
*Src~S~*.
Copy link

@williamih williamih Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be Scope src not Src S? And similarly for the destination scope below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea.

Going back and forth on those var names. Suggestions?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm - Scope~src makes sense to me. I think that may be better than Src S because in some places in the spec the variable S is used to mean a synchronization command (rather than a scope).

Other people may have more ideas though!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*Scope~src~* is fine, though I'd be tempted to call it *Scope~first~* (and second) to match the wording in the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tobski The nomenclature is sorta mixed. The API parameters use src/dst. TBH I like it more because first/second does not convey a difference between the scope in how they are used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We landed on first/second for some reason that I honestly can't entirely remember. I'm fine with src/dst here, but might be worth considering a nomenclature change for the spec elsewhere to match - though I'd do that in a separate MR because that's going to be churny.

* Let *Ops~dst~* be the subset of operations in *Ops* selected by scope
*Dst~S~*.
* Submitting *S* for execution will result in an execution dependency *ED*
between *Ops~src~* and *Ops~dst~*.
* Execution dependency *ED* guarantees that *Ops~src~* happens-before
*Ops~dst~*.

[[synchronization-dependencies-chains]]
An _execution dependency chain_ is a sequence of execution dependencies that
form a happens-before relation between the first dependency's *A'* and the
final dependency's *B'*.
For each consecutive pair of execution dependencies, a chain exists if the
intersection of *B~S~* in the first dependency and *A~S~* in the second
dependency is not an empty set.
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 *A~S~* be the first synchronization scope of the first command in
*S*.
* Let *B~S~* be the second synchronization scope of the last command in
*S*.
A sequence of execution dependencies can: form a transitive property called
an _execution dependency chain_.
An _execution dependency chain_ is formed between any and all two execution
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
An _execution dependency chain_ is formed between any and all two execution
An _execution dependency chain_ is formed between any two execution

Unnecessary verbage, easier to read without IMO.

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is sort of a legal doublet. "any and all" means "every". "any" alone is not exhaustive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, I get it, but we consistently use "any" for this meaning by itself, precisely for the reasons I mentioned above. It'd be inconsistent to change that now.

dependencies whenever there is an overlap in the first dependency's
*Scope~dst~* and subsequent dependency's *Scope~src~*.
There is an overlap between two scopes if it is not possible to reduce the
combination of the selection criteria of the *Scope~dst~* and the
*Scope~src~* to nothing.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This language is a bit awkward. I'm inclined to say this is where using set theory makes sense. This is a definite intersection of two sets of the same type, and I'd suggest rewording it as such.

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is best I came up with yet.

Problem is if you want it to be set intersection of same types, then what is the type? Set theory gives the wrong idea here and the wrong type of arithmetic. What I want here is "merger of two SQL queries" and not a set intersection. If I wanted set intersection, I would need a static type that forms static sets, which I can cleanly invoke set operations on. But scopes are sort of dynamic types. They are a predicate. You cannot make a set intersection of predicates. As far as I know (because nominally differing predicates can still have a common overlap, but that is not covered by set intersection operation. In a set intersection, elements are either completely identical or they are completely different and nothing between that.). If we really want to go uberformal, we need to introduce bunch of predicate logic theory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've identified the two scopes as "sets of selection criteria" so you've identified the type already; calling out the intersection of those two sets as non-null suggests the selection criteria is empty. The only ambiguity here is whether this is an inclusive or exclusive set of criteria, which I don't think would be hard to clarify, and would dictate whether to use union or intersection here. The "predicate" idea you've suggested isn't something you've written down in this PR yet, and I'm not sure it would add anything.

We certainly can't introduce SQL queries as a concept in the Vulkan spec though 😛.

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it does not unfortunately work that way. Consider this:

criterion1: "All operations after S1"
criterion2: "All operations before S2"

The strings are clearly different and the criteria are clearly different, therefore set intersection of set {criterion1} and set {criterion2} is an empty set {}, because criterion1 ≠ criterion2.

But the predicate criterion1 ∧ criterion2 yields a new nonempty (resp. non-tautological) predicate "All operations after S1 and before S2".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused, that sounds like exactly what we want? Where's the problem here?

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is set logic (set intersection) yields empty result, wheere predicate logic (predicate-and) would yield non-empty result (resp. technically non-tautological resulting predicate, without first prematurely evaluating the predicates). We want the predicate logic, and we do not want the set logic for the purposes of determining whether chain is formed. Therefore we cannot use set intersection to describe this, unless we invoke "ethereal operations" as the type of the elements of the set, which would be its own can of worms.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see what you're trying to get at here, I don't think the "hypothetical operations" is a much a can of worms as you think it is, and I'm half tempted to go draft that MR so we can compare.

In lieu of doing that though, it sounds like you have an idea to frame this as a sort of database query, which is a perfectly reasonable mental model, but I suspect that if you want to make the spec work that way, you've got a LOT more work to do. I'm concerned that by combining concepts like this PR is currently doing we're heading into a rabbit hole that will just confuse things more.

Like I think you have a vision here for how it's going to work, and it's not the one the spec has currently, and that's fine, but I don't know yet if there's any merit to that framing over what we've currently got.

Based on the discussion in #1815, it felt to me like there was a much smaller fix to that issue, and I'm concerned this PR is starting to drift too far from just solving that original issue. The set of changes to make it deal in "hypothetical operations" I suspect is much smaller.

Copy link
Contributor Author

@krOoze krOoze Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My problem with "hypothetical operation" is that forms a set of something unreal, magic, and uncountable. Can't say for sure without seeing this alternative, but I feel it will lead to similar vagueness as the original Issue points out. At least when sufficiently literal reader reads that.

After thinking about it. introducing "hypothetical operations" is sort of a hack\hotfix. And predicate logic is the appropriate indirection method to solve describing this situation. As it is now in the PR, it probably is not good either. But it feels one approach cannot be sufficiently formalized no matter how much one tries, while the other fundamentally can. I think the formalism is probably unavoidable, so I should steer the draft that way over the weekend. I could attempt to first make some quick fix if you want, but not sure if it is productive thing to do rather than a doubling of work.

I would avoid the tempting dopamine hit of promptly closing an Issue. I admit I am not a believer in atomic fixes. It is a rare day when something is amenable to fixing atomically in a way it never comes up in subsequent issues. Something top-down and interwoven as the sync system needs some care. At the minimum I consider the whole section to be undivisible and in need to be always edited as a whole.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I disagree with much of that, except for your assertion that the other approach can't be formalized. Editing this chapter is hard. I agree that "hypothetical operation" may look like a hotfix and won't know until I try writing it out though.

There's an internal task to rewrite all of this incorporating the memory model language much better, because as you've pointed out there's no formal definition of happens-before without it, and literally nobody is looking forward to it :)
Because of that I'm a tad wary of a major rewrite just now; was hoping that you'd be able to get more with less here.

Ultimately, I tend to stick by the philosophy that "less is more" - if editing a chapter results in less words then it's a clear win. If it's about the same number of words then it's a much tougher sell. If there's more words, you've probably made it harder. This is a bit of a rough metric but I do find it helps when reviewing. So the thing I'd suggest is if you are planning on doing a lot of work here, plan it out first and try to find ways to say more with less. If you can reduce the number of concepts needed, I'd be much more inclined to approve this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, less words I can give you easily. Just delete all the words :p. Unfortunatelly there is another overriding priority: the words must describe completely, correctly, and coherently (4C) the things they describe.

It is unlikely I can substract concepts, because the Issue implies there actually is a concept missing (or not fully formed). What I try to do is first try to find the ideal state, and only then worry how I get there. Planning a route to a destination you don't know is a tricky business. Anyway I am happy with the name changes, which could now be a neat and likely noncontroversial patch that helps reasoning about all this stuff without getting lost.


[NOTE]
.Note
====
For example, if a flink:vkCmdPipelineBarrier has pname:dstStageMask of
ename:VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, and subsequent
flink:vkCmdPipelineBarrier has pname:srcStageMask of
ename:VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, the combined selection
criterion of both is "commands occuring later than the first barrier and
earlier than the second barrier reduced to the operations in
ename:VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
ename:VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
Copy link

@williamih williamih Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a really helpful example.

I have one question about this. I could be wrong, but I'm thinking VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT might not be included in the combined selection criteria, because this stage happens before the fragment shader stage - does that seem correct to you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copypasta error. I think they are listed this way in the enum, but in the graphics pipe there's just late test inbetween

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not keen on this specific example because it leans on the pipeline stage order, which isn't defined yet. I'd rather we highlight a simpler example here to avoid new readers getting confused - e.g. something that includes exactly the same stages directly. We could then elaborate on this example later when pipeline stage order is introduced to get that concept highlighted better (which might be a good improvement regardless).

For us I think this example makes sense, because we've read the spec and are familiar - but for a new reader this would be confusing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think examples might make clear some of the abstract language of scopes and dependencies. So I encourage that.

Copy link
Contributor Author

@krOoze krOoze Apr 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tobski I try to make as brutal example here as possible. I suppose it is sort of a desperate attempt to compensate the lack of sufficiently formal description of what "scope overlap" is...

In my mind the concept is pretty straightforward, so it is mindly annoying that it might probably require like half a page to properly explain in the end. And even so will still probably require an example to have some certainty people grok it correct.

@stonesthrow Yea. I mean a presence of an example (similarly to code comments) indicates that the formal specifying text is lacking. But then again it is better to have crappy specifying language and an example, than have a crappy specifying language and no example...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krOoze I don't disagree with your intent, but I do think a fresh reader would not be able parse this particular example until they've gone and read a lot more of the chapter. IMO we need something in the style of the Vulkan Guide or a proposal document - where you get a much higher level view of things without all the formality. There you could say a lot of this much more straightforwardly.

In the meantime, I'd rather we simplify this particular example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tobski I was kinda strategically aiming for something hard. This is the where reader needs to slow down. The example demonstrates the original Issue. I suppose I can sacrifice the implicit pipeline stage part of the example for now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the pipeline stage order is really my main concern here - the rest is fine.

ename:VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
and ename:VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT stages".
That is a valid non-empty selection criterium, therefore an
_execution dependency chain_ is formed between these two barriers.

Only the order of submission of the synchronization operations, and its
scopes matter for determining whether an _execution dependency chain_ has
been formed. There need not be any operation actually executed inbetween the
two synchronization operations for a chain to form. Only the selection
criteria matters for determining this, and whether actual real executed
operations are being selected or not is irrelevant.
====

Synchronization operations that formed an _execution dependency chain_ in
addition to introducing their individual
<<synchronization-dependencies-execution,execution dependencies>> also
introduce and additional third execution dependency.
This additional dependency guarantees that the first dependecy's *Ops~src~*
_happen-before_ the second dependency's *Ops~dst~*.
This dependency can: itself also form a chain with another execution
dependency, which can form an _execution dependency chain_ of more than two
depenencies.
_Execution dependency chain_ complements the specification of individual
execution dependencies with the following description:
Comment on lines +129 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit looser than I'd like, maybe:

Suggested change
Synchronization operations that formed an _execution dependency chain_ in
addition to introducing their individual
<<synchronization-dependencies-execution,execution dependencies>> also
introduce and additional third execution dependency.
This additional dependency guarantees that the first dependecy's *Ops~src~*
_happen-before_ the second dependency's *Ops~dst~*.
This dependency can: itself also form a chain with another execution
dependency, which can form an _execution dependency chain_ of more than two
depenencies.
_Execution dependency chain_ complements the specification of individual
execution dependencies with the following description:
An _execution dependency chain_ implicitly creates another
<<synchronization-dependencies-execution,execution dependency>>.
An execution dependency formed in this way guarantees that *Ops~src~*
in the first dependency in the chain _happens-before_ *Ops~dst~* in the
second dependency in the chain.
This new dependency can: itself become part of another chain, forming an
_execution dependency chain_ of multiple dependencies, up to and including
all operations in the application.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the difference. Can you point out what the underlying loosness is?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Literally number of words needed to state the same concepts.


* Let *S~1~*, *S~2~*, ..., *S~N~* be a list of *N* synchronization
commands submitted in this order.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you're leaning on submission order, which hasn't been introduced yet. In the execution dependency definition you did an excellent job of getting rid of this, and I think we could repeat that here.

The order of operations is unnecessary if you can formally define the way an execution dependency chain is formed by the intersection of scopes between operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea it is just the chain of synch dependencies.

* Let's assume *S~1~*, *S~2~*, ..., *S~N~* are all part of an
_execution dependency chain_ *EC* such that *S~N~* is directly or
transitively chained with *S~1~*.
* Let *Scope~src~* be the first synchronization scope of *S~1~*.
* Let *Scope~dst~* be the second synchronization scope of *S~N~*.
* The chain *EC* introduces same
<<synchronization-dependencies-execution,execution dependency>>
guarantees as if instead an individual synchronization command *S* was
executed with these *Scope~src~* and *Scope~dst~* scopes.

Execution dependencies alone are not sufficient to guarantee that values
resulting from writes in one set of operations can: be read from another set
of operations.

[[synchronization-dependencies-available-and-visible]]
Three additional types of operations are used to control memory access.
_Availability operations_ cause the values generated by specified memory
write accesses to become _available_ to a memory domain for future access.
Any available value remains available until a subsequent write to the same
memory location occurs (whether it is made available or not) or the memory
is freed.
_Memory domain operations_ cause writes that are available to a source
memory domain to become available to a destination memory domain (an example
of this is making writes available to the host domain available to the
device domain).
_Visibility operations_ cause values available to a memory domain to become
_visible_ to specified memory accesses.
Three additional types of operations are used to control memory access:

* _Availability operations_ cause the values generated by specified memory
write accesses to become _available_ in a specific memory domain for
future access.
Any available value remains available until a subsequent write to the
same memory location occurs (whether it is made available or not) or the
memory is freed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC these spaces lead to unnecessary gaps in the bullet list, as asciidoctor treats them as separate lists, so would like them removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry too much about formatting for now. I will self-review stuff if and when we dedraft this and I will render it and run spellcheck.

* _Memory domain operations_ cause writes that are available in a source
memory domain to become available in a destination memory domain (an
example of this is making writes available in the host domain available
in the device domain).

* _Visibility operations_ cause values available in a specific memory
domain to become _visible_ to specified memory accesses.

ifdef::editing-notes[]
[NOTE]
.editing-note
====
It feels the following is kinda important and should be part of core 1.0
Vulkan to some extent.
====
endif::editing-notes[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we hope to better integrate the memory model appendix with the synchronization chapter in general, it's just not something we've had the resource to do, yet - I'm not sure an editors note here is necessary as this is tracked internally, but I'm not particularly against including it. For now we've just hidden it behind the extension as some of the definitions only somewhat apply without it.

Mostly just adding some context here, not necessarily suggesting a change.

Copy link
Contributor Author

@krOoze krOoze Apr 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Particularly the "happens-before\after" is frequently used, so should be integrated with the core spec sooner rather than later...


ifdef::VK_VERSION_1_2,VK_KHR_vulkan_memory_model[]
Availability, visibility, memory domains, and memory domain operations are
Expand All @@ -137,32 +203,34 @@ they can: be read or written by that type of memory access.
Most synchronization commands in Vulkan define a memory dependency.

[[synchronization-dependencies-access-scopes]]
The specific memory accesses that are made available and visible are defined
by the _access scopes_ of a memory dependency.
The specific memory accesses that are made available and visible are
selected by the criteria in _access scopes_ of a memory dependency.
Any type of access that is in a memory dependency's first access scope and
occurs in *A'* is made available.
occurs in *Ops~src~* is made available.
Any type of access that is in a memory dependency's second access scope and
occurs in *B'* has any available writes made visible to it.
Any type of operation that is not in a synchronization command's access
scopes will not be included in the resulting dependency.
occurs in *Ops~dst~* has any available writes made visible to it.
Any type of operation and access that is not selected by synchronization
command's access scopes will not be included in the resulting dependency.

A memory dependency enforces availability and visibility of memory accesses
and execution order between two sets of operations.
Adding to the description of <<synchronization-dependencies-chains,
execution dependency chains>>:

* Let *a* be the set of memory accesses performed by *A'*.
* Let *b* be the set of memory accesses performed by *B'*.
* Let *a~S~* be the first access scope of the first command in *S*.
* Let *b~S~* be the second access scope of the last command in *S*.
* Let *a'* be the intersection of sets *a* and *a~S~*.
* Let *b'* be the intersection of sets *b* and *b~S~*.
* Submitting *A*, *S* and *B* for execution, in that order, will result in
a memory dependency *m* between *A'* and *B'*.
* Memory dependency *m* guarantees that:
** Memory writes in *a'* are made available.
** Available memory writes, including those from *a'*, are made visible to
*b'*.
* Let *OpsMem~src~* be the set of memory accesses performed by *Ops~src~*.
* Let *OpsMem~dst~* be the set of memory accesses performed by *Ops~dst~*.
* Let *AccessScope~src~* be the first access scope of *S~1~*.
* Let *AccessScope~dst~* be the second access scope of *S~N~*.
* Let *Accesses~src~* be the subset of memory accesses in *OpsMem~src~*
selected by access scope *AccessScope~src~*.
* Let *Accesses~dst~* be the subset of memory accesses in *OpsMem~dst~*
selected by access scope *AccessScope~dst~*.
* Submitting *S* for execution will result in an execution dependency *ED*
between *Ops~src~* and *Ops~dst~*.
* Memory dependency *MD* guarantees that:
** Memory writes in *Accesses~src~* are made available.
** Available memory writes, including those from *Accesses~src~*, are
made visible to *Accesses~dst~*.

[NOTE]
.Note
Expand Down Expand Up @@ -833,13 +901,13 @@ pipeline stage must: not happen-before completion of a logically earlier
stage.
This means that including any stage in the source stage mask for a
particular synchronization command also implies that any logically earlier
stages are included in *A~S~* for that command.
stages are included in *Scope~src~* for that command.

Similarly, initiation of a logically earlier pipeline stage must: not
happen-after initiation of a logically later pipeline stage.
Including any given stage in the destination stage mask for a particular
synchronization command also implies that any logically later stages are
included in *B~S~* for that command.
included in *Scope~dst~* for that command.

[NOTE]
.Note
Expand Down