I have some clarifying questions on how fences work in Metal 4.
- If two encoders A, B update the same fence and encoder C waits on that fence, is the work encoded by C guaranteed to execute after both A and B have completed, or after either A or B have completed? The following quotes in the waitForFence() documentation seem contradictory.
- "Encodes a command that instructs the GPU to pause before starting one or more stages of the pass until a pass updates a fence."
- "When encoding a pass that reuses a fence, wait for other passes to update the fence before repurposing that fence..."
- Are fences unsignaled when they are waited on? Specifically, can two (or more) encoders wait on a fence that is only updated in a single prior encoder?
- If an encoder updates a fence, no subsequent encoders in the command queue wait on the fence, and the command queue is committed, is that fence still signaled when used in a subsequent command buffer?
Thanks for quoting the exact passages, which makes the wording easy to compare.
C waits for both A and B. The Synchronizing passes with a fence article says the GPU pauses before running the commands that follow the wait "until the GPU runs all update commands you encode for the same fence in the other relevant, producing passes." The waitForFence(_:beforeEncoderStages:) declaration in MTL4CommandEncoder.h also says that work "doesn't begin until all prior updates to the fence is complete." The second passage you quoted comes from the section "Reuse a fence by waiting first and updating second," which describes a single pass that waits on a fence and then updates it.
On whether a wait resets the fence: the documentation describes waits only in terms of prior updates. It doesn't say that a wait resets a fence, and it doesn't limit how many passes can wait for the same update. The article does say, "You can reuse a fence instance to resolve resource access conflicts in subsequent commands after encoding a wait command for a pass."
On fences across command buffers: the article says, "A fence resolves access conflicts between commands in different passes that you submit to the same command queue, including the passes you commit in other command buffers." The MTLFence documentation adds, "When submitting the producing and consuming passes in different command buffers, commit the command buffers with the producing passes before those with the consuming passes."
The method page's summary says "until a pass updates a fence." If that's what suggested the either-or reading, please consider filing a documentation report using Feedback Assistant. It could cover that wording and say whether a wait consumes a fence update, or whether several passes can wait on the same update.