Race conditions when changing CAMetalLayer.drawableSize?

Is the pseudocode below thread-safe? Imagine that the Main thread sets the CAMetalLayer's drawableSize to a new size meanwhile the rendering thread is in the middle of rendering into an existing MTLDrawable which does still have the old size.

Is the change of metalLayer.drawableSize thread-safe in the sense that I can present an old MTLDrawable which has a different resolution than the current value of metalLayer.drawableSize? I assume that setting the drawableSize property informs Metal that the next MTLDrawable offered by the CAMetalLayer should have the new size, right?

Is it valid to assume that "metalLayer.drawableSize = newSize" and "metalLayer.nextDrawable()" are internally synchronized, so it cannot happen that metalLayer.nextDrawable() would produce e.g. a MTLDrawable with the old width but with the new height (or a completely invalid resolution due to potential race conditions)?

func onWindowResized(newSize: CGSize) {
    // Called on the Main thread
    metalLayer.drawableSize = newSize
}

func onVsync(drawable: MTLDrawable) {
    // Called on a background rendering thread
    renderer.renderInto(drawable: drawable)
}

You'd most likely want to have these both called on the same thread, so never at the same time. This is the default behavior from MTLView.

With above assumption: Your onVsync() call uses existing members to record rendering operations. As such, any created command buffer has references to objects existing with the old size. Due to ref-counting mechanism, these objects have their refcount increased when they get recorded in the command buffer.

Now when onWindowResized() is called, you'd recreate these member resources. By doing so, your class loses references to the resources potentially still in use by the previously recorded command buffer. However, since the command buffer holds its own strong references to these, it's not an issue.

So when recreating resources, you're effectively just preparing Metal resources that'll be used in the next onVsync() call.

If you modify (rather than recreate) resources used by still in-flight command buffers, then you can indeed run into concurrency issues.

And if you have both methods called on distinct threads like you initially suggested, you not only have a resource consistency issue with the GPU, but also a potential race condition on your CPU code.

Race conditions when changing CAMetalLayer.drawableSize?
 
 
Q