-
Notifications
You must be signed in to change notification settings - Fork 335
Multi-queue synchronization #1169
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
Changes from all commits
940065f
adaa652
0c5f268
f4eb24d
43ecfb9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2018,6 +2018,8 @@ dictionary GPUTextureViewDescriptor : GPUObjectDescriptorBase { | |
}; | ||
</script> | ||
|
||
Issue: derive from `GPUTextureSubresourceRange` | ||
|
||
Issue: Make this a standalone algorithm used in the createView algorithm. | ||
|
||
Issue: The references to GPUTextureDescriptor here should actually refer to | ||
|
@@ -6321,8 +6323,35 @@ dictionary GPURenderBundleEncoderDescriptor : GPUObjectDescriptorBase { | |
# Queues # {#queues} | ||
|
||
<script type=idl> | ||
typedef [EnforceRange] unsigned long long GPUSignalValue; | ||
|
||
dictionary GPUTextureSubresourceRange { | ||
GPUTextureAspect aspect = "all"; | ||
GPUIntegerCoordinate baseMipLevel = 0; | ||
GPUIntegerCoordinate mipLevelCount; | ||
GPUIntegerCoordinate baseArrayLayer = 0; | ||
GPUIntegerCoordinate arrayLayerCount; | ||
}; | ||
|
||
dictionary GPUTextureSubresources: GPUTextureSubresourceRange { | ||
required GPUTexture texture; | ||
}; | ||
|
||
dictionary GPUResourceTransfer { | ||
required GPUQueue receivingQueue; | ||
required sequence<GPUBuffer> buffers; | ||
required sequence<GPUTextureSubresources> textureSubresources; | ||
}; | ||
|
||
interface GPUQueue { | ||
undefined submit(sequence<GPUCommandBuffer> commandBuffers); | ||
GPUSignalValue signal(); | ||
readonly attribute GPUSignalValue lastSignaledValue; | ||
|
||
undefined waitFor(GPUQueue queue, optional GPUSignalValue value); | ||
|
||
undefined submit( | ||
sequence<GPUCommandBuffer> commandBuffers, | ||
optional sequence<GPUResourceTransfer> transfers = []); | ||
|
||
GPUFence createFence(optional GPUFenceDescriptor descriptor = {}); | ||
undefined signal(GPUFence fence, GPUFenceValue signalValue); | ||
|
@@ -6350,6 +6379,14 @@ GPUQueue includes GPUObjectBase; | |
|
||
{{GPUQueue}} has the following methods: | ||
|
||
<dl dfn-type=attribute dfn-for=GPUQueue> | ||
: <dfn>lastSignaledValue</dfn> of type {{GPUSignalValue}}, readonly | ||
:: | ||
Returns the integer value that is higher or equal to all the values | ||
previously returned by either {{GPUQueue/lastSignaledValue}} or | ||
{{GPUQueue/signal()}} on this queue. | ||
</dl> | ||
|
||
<dl dfn-type=method dfn-for=GPUQueue> | ||
: <dfn>writeBuffer(buffer, bufferOffset, data, dataOffset, size)</dfn> | ||
:: | ||
|
@@ -6498,8 +6535,10 @@ GPUQueue includes GPUObjectBase; | |
**Called on:** {{GPUQueue}} this. | ||
|
||
**Arguments:** | ||
<pre class=argumentdef for="GPUQueue/submit(commandBuffers)"> | ||
|commandBuffers|: | ||
<pre class=argumentdef for="GPUQueue/submit(commandBuffers, transfers)"> | ||
|commandBuffers|: list of {{GPUCommandBuffer}} to execute. | ||
|transfers|: list of {{GPUResourceTransfer}} that represent transferring | ||
resource ownership from this {{GPUQueue}} to the others. | ||
</pre> | ||
|
||
**Returns:** {{undefined}} | ||
|
@@ -6516,9 +6555,30 @@ GPUQueue includes GPUObjectBase; | |
<div class=queue-timeline> | ||
1. For each |commandBuffer| in |commandBuffers|: | ||
1. Execute each command in |commandBuffer|.{{GPUCommandBuffer/[[command_list]]}}. | ||
1. For each |transfer| in |transfers|: | ||
1. Transfer the |transfer|.{{GPUResourceTransfer/buffers}} to | ||
|transfer|.{{GPUResourceTransfer/receivingQueue}}. | ||
1. Transfer the |transfer|.{{GPUResourceTransfer/textureSubresources}} to | ||
|transfer|.{{GPUResourceTransfer/receivingQueue}}. | ||
</div> | ||
</div> | ||
</div> | ||
|
||
: <dfn>waitFor(queue, value)</dfn> | ||
:: | ||
Waits for the |queue| reaching |value| on the [=Queue timeline=]. If |value| is undefined, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Wait" sounds like it might cpu-block.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually we should consider renaming There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 for |
||
the |queue|.{{GPUQueue/lastSignaledValue}} is used instead. | ||
|
||
The |value| has to be less or equal to the |queue|.{{GPUQueue/lastSignaledValue}}, | ||
or a validation error is produced. | ||
|
||
All the resource transitions from |queue| targeting |this| will be considered done on the [=Queue timeline=] | ||
after this call, and relevant resources can be used on |this|. | ||
kvark marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
: <dfn>signal()</dfn> | ||
:: | ||
Returns a signal value corresponding to the work submitted to the queue up to this moment on the [=content timeline=]. | ||
This value has to be higher or equal to return value of the previous call to {{GPUQueue/signal()}} on this queue. | ||
</dl> | ||
|
||
## <dfn interface>GPUFence</dfn> ## {#fence} | ||
|
@@ -6601,7 +6661,6 @@ The completion of the fence and the value it completes with can be observed from | |
: <dfn>onCompletion(completionValue)</dfn> | ||
:: | ||
Returns a {{Promise}} that resolves once the fence's completion value ≥ `completionValue`. | ||
|
||
<div algorithm="GPUFence.onCompletion"> | ||
**Called on:** {{GPUFence}} this. | ||
|
||
|
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 does the PR description mean when it says "because they also need to take into account writeBuffer and writeTexture?"
I would have expected that after
submit
returns control to the caller, the developer is free to use the resources in the transfer list on the receiving queue and the WebGPU implementation handles setting up the fences as needed to avoid undefined behavior. What is the advantage of having the developer do this themselves?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 what's meant here is: "Getting signal values and waiting on signals are separate queue operations, rather than rolled into the submit() call, because writeBuffer and writeTexture also submit work to the queue. This avoids having to extend all three functions (submit, writeBuffer, and writeTexture) to return signal values and be able to wait on signals."
We shouldn't just implicitly insert a wait() on the receiving queue at whatever arbitrary time the app happens to issue the transferring submit on the sending queue. The app needs to have control over what point in the receiving queue the resources are received, otherwise the receiving queue can stall too early and go idle when it shouldn't have to.
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 would be sub-optimal to insert a wait on the receiving queue at the time of the transferring submit. Why can't we insert a wait the first time you submit a command list with the object to the receiving queue? Wouldn't we need to run the same logic to validate the developer hasn't missed a wait? Missing a wait would lead to undefined behavior.
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.
Because that would make the graph of synchronization implicit. Missing a wait would cause a validation error and not UB. As said in the meeting I'll detail more what the thought process was for this proposal.