[CAMetalLayer nextDrawable] return nil

I have created a separate thread for rendering task. And it is not vsynced which means the thread could generate frames multiple times within one vsync. Because it generates frames faster than GPU, [CAMetalLayer nextDrawable] would sometime wait a whole vsync time to return a valid drawable. But after a few good frames, [CAMetalLayer nextDrawable] begins to return nil. Is this bug of metal? Although the document says this is due to incorrect configuration of CAMetalLayer, I am sure my configuration is done correctly.

Replies

Does your rendering thread have an autorelease pool in place that is getting drained each frame? If not your CAMetalDrawable objects probably just aren't being released and so the underlying buffers never get recycled.

Yes. autorelease pool is in place.

We hit something similar --- our app update thread is separate from the OS tick thread (i.e. CADisplayLink just gates our update thread, doesn't run the update directly). Rendering is done on yet another thread.


We were creating our UIView with Metal backing in our update thread, which caused the same problem you see. Drawables failed after three. This always worked fine under GLES.


The creation needed to be pushed to the main app thread - (via performSelectorOnMainThread), then the drawable autorelease pool worked fine.


Several apple engineers investigated - nobody could give a solid explanation why.

Sorry in case I wasn't clear


"The creation needed...." == "The VIEW creation needed..."

Thank you very much, this resolved the issue for me. Same as everyone else, I get 3 CAMetalDrawable's from nextDrawable then pauses in nextDrawable and nils back for approx 5 seconds, then CAMetalDrawables again for ever. Weird. Autorelease pool fixed it right up.

It seems that CAMetalLayer initizalization needs to be executed on the main thread:

cametallayer-initialization-only-works-on-main-thread (stackoverflow)


I do not have an explanation for this being the case though because in general CALayer initialization does not need to be done on the main thread.