-
Notifications
You must be signed in to change notification settings - Fork 335
Synchronization section of the spec #557
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
spec/index.bs
Outdated
at the [=usage scope=] boundaries. | ||
|
||
This specification defines the following [=usage scopes=]: | ||
1. an individual copy command on a {{GPUCommandEncoder}}, such as {{GPUCommandEncoder/copyBufferToTexture()|GPUCommandEncoder.copyBufferToTexture}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or just "an individual command on a ..."
spec/index.bs
Outdated
|
||
This specification defines the following [=usage scopes=]: | ||
1. an individual copy command on a {{GPUCommandEncoder}}, such as {{GPUCommandEncoder/copyBufferToTexture()|GPUCommandEncoder.copyBufferToTexture}}. | ||
2. an individual command inside a {{GPUComputePassEncoder}}, such as {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)|GPUProgrammablePassEncoder.setBindGroup}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually isn't it just dispatch and dispatch indirect that are usage scopes? The rest are just setting state for these two commands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great question to raise. The reason I went for any command here is apposed to just the draws, is because it would be awkward to allow bad state to be bound even if it's not used.
So, first, I think we are going to be specifying the exact resources used by a dispatch as those that are covered by the bind groups attached to slots expected by the layout of the active pipeline. So there might be bindings not included/used by a dispatch, and similarly for the draws.
What happens if, for example, the user is recording a render pass, and they bind a group that uses one of the current render targets as STORAGE? It seems to me that making this an error versus non error based on the dependencies of a draw() would make up for a weaker API. It would be nice to specify that, in particular, everything you bind within a render pass becomes part of the usage scope for this pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed explanation. It makes a lot of sense for the render pass. For the dispatch we'd want to consider the resources used by that dispatch and only this one so the wording might get a bit more complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the user does setBindGroup()
with one that is self-conflicting? I.e. it has different mutable bindings for the same resource? If we spec the usage scopes for dispatch
only, we'd be ignoring these bindings, potentially.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what's best here. Both validating the setBindGroup
by itself and not doing it seem weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to be somewhat consistent between the compute and render passes wrt the usage scopes, even if the scopes are different. I.e. it would be good to say that the usage scope of a render pass is the union of the usage scopes of its commands, and for the compute pass it's just not a union.
So the same kind of problem can be seen in render passes: if the user calls setVertexData
we have a choice (in how we define the usage scopes):
- Every command by itself is a usage scope, and the render pass considers the union of all usage scopes of its commands. This is what the current PR has (or at least aims to). The consequence here is that we consider the vertex buffer to be used by the pass (regardless of what the draw calls would do).
- Only draws, dispatches, and copies are considered to be the usage scopes (and a render pass is a union of its draw usage scopes). This means that on each
draw()
we would have to traverse the dependencies and consider the usage scopes. In this case, it will be up to the active render pipeline layout at the nextdraw()
to decide whether the vertex buffer is considered to be used.
I have a slight preference towards (1) for making the validation simpler, which may allow us to have higher draw call throughput in the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense that calling setVertexBuffer will mark the buffer as used for that pass even if it's not actually accessed by the draw call. It's up to the developer to prevent that from happening if they want to use a vertex buffer as something else during that pass.
spec/index.bs
Outdated
For example, it can check if all the bindings inside a single {{GPUBindGroup}} make a valid usage scope | ||
that would be considered every time {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)}} is called. | ||
|
||
Issue: Should a created bind group then be considered invalid? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I don't think it's useful for implementations to do early validation like this because it only optimizes the error case, not the success case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't have strong feelings about this. Will remove the issue.
spec/index.bs
Outdated
Timeline could be split into a sequence of [=usage scope=]: | ||
within each scope the usage of the [=subresource=] stays unchanged, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Timeline could be split into a sequence of [=usage scope=]: | |
within each scope the usage of the [=subresource=] stays unchanged, | |
The [=Queue timeline=] is split into a sequence of [=usage scope=]s. | |
Within each scope the usage of the [=subresource=] stays unchanged, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In multiqueue, there's one queue timeline per queue, right? Hard to say now, but there needs to be at least some synchronization at the device timeline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be up to the multi-queue proposal to specify.
{{GPUQueue/submit(commandBuffers)}} does nothing and produces an error if any of the following is true: | ||
|
||
- Any {{GPUBuffer}} referenced in any element of `commandBuffers` isn't in the `"unmapped"` [=buffer state=]. | ||
- Any of the [=usage scopes=] contained in the command buffers fail the [=usage scope validation=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Any of the [=usage scopes=] contained in the command buffers fail the [=usage scope validation=]. | |
- Any of the [=usage scopes=] contained in the command buffers fail [=usage scope validation=]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why the
shouldn't be here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it shouldn't be there, but kind of okay either way: "if any X fail validation." vs "if any X fail the validation."
spec/index.bs
Outdated
which have been validated for correct resource usage during recording on the [=Content timeline=], | ||
results in the resource usage also being valid at the [=Queue timeline=]. | ||
|
||
The implementation does the <dfn dfn>usage scope validation</dfn> by composing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation does the <dfn dfn>usage scope validation</dfn> by composing | |
The implementation performs <dfn dfn>usage scope validation</dfn> by composing |
spec/index.bs
Outdated
|
||
The implementation does the <dfn dfn>usage scope validation</dfn> by composing | ||
the union of all usage flags of the [=subresources=] used by the [=usage scope=]. | ||
The {{GPUValidationError}} is generated in the current scope with appropriate error message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The {{GPUValidationError}} is generated in the current scope with appropriate error message | |
A {{GPUValidationError}} is generated in the current scope with appropriate error message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good so far.
spec/index.bs
Outdated
Timeline could be split into a sequence of [=usage scope=]: | ||
within each scope the usage of the [=subresource=] stays unchanged, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In multiqueue, there's one queue timeline per queue, right? Hard to say now, but there needs to be at least some synchronization at the device timeline.
spec/index.bs
Outdated
if the union contains a [=mutating usage=] combined with any other usage. | ||
|
||
Note: an implementation is likely to validate the usage scopes earlier | ||
than at {{GPUQueue/submit()|GPUQueue.submit}} time, where the [=Queue timeline=] is defined. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
than at {{GPUQueue/submit()|GPUQueue.submit}} time, where the [=Queue timeline=] is defined. | |
than at {{GPUQueue/submit()|GPUQueue.submit}} time (which occurs on the [=Queue timeline=]). |
spec/index.bs
Outdated
For example, it can check if all the bindings inside a single {{GPUBindGroup}} make a valid usage scope | ||
that would be considered every time {{GPUProgrammablePassEncoder/setBindGroup(index, bindGroup, dynamicOffsets)}} is called. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what this is saying; we can talk about it on the editors call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved: We don't need this particular bit. But we should move the validation from submit() to finish().
spec/index.bs
Outdated
{{GPUBindingType/"sampled-texture"}}, |view|'s texture's {{GPUTextureDescriptor/usage}} | ||
must include {{GPUTextureUsage/SAMPLED}}. | ||
must include {{GPUTextureUsage/SAMPLED}}. The texture's [=subresources=] seen by the |view| | ||
are considered to be [=used=] by the resulting bind group as {{GPUTextureUsage/SAMPLED}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make this more formal (put the subresource usages in a list, or something), but it can definitely be done later
Rewrite the usage validation section to tell that it happens at finish() time. Add "usedBuffers" and "usedTextures" internal slots to "GPUBindGroup".
I addressed the changes we discussed and rebased this. The validation is described to happen at
We can do this as a follow-up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll open a PR with some small nits.
|
||
Issue: This section will need to be redacted to support multiple queues. | ||
|
||
The [=Queue timeline=] could be split into a sequence of [=usage scopes=]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this supposed to be part of the Issue? If not, then "could" doesn't make sense here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, it's not a part of the issue. I was trying to say that we can consider the queue timeline to be seen as a sequence of usage scopes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then I think the version I have in the "nits" should be what you intended.
* Syncronization section * Address Kang's notes * Address Kai's comments. Rewrite the usage validation section to tell that it happens at finish() time. Add "usedBuffers" and "usedTextures" internal slots to "GPUBindGroup".
* Syncronization section * Address Kang's notes * Address Kai's comments. Rewrite the usage validation section to tell that it happens at finish() time. Add "usedBuffers" and "usedTextures" internal slots to "GPUBindGroup".
It's very rough, hoping to get feedback to make it better. It's supposed to cover the important missing bits about what the actual usage scopes are, and how the validation is done.
Preview | Diff