I do have a straight forward CAMetalLayer setup, except the CAMetalLayer is initialized on a global thread, which looks like this (call init, setup basic properties and add as sublayer):
DispatchQueue.global().async {
let renderLayer = CAMetalLayer()
renderLayer.isOpaque = false
renderLayer.frame = frame
renderLayer.drawableSize = drawableSize
renderLayer.framebufferOnly = false
renderLayer.device = metalDevice
renderLayer.pixelFormat = metalPixelFormat
renderLayer.contentsScale = contentScale
DispatchQueue.main.async {
view.layer.addSublayer(renderLayer)
}
}
This code runs without any runtime errors, but unfortunately when rendering to the CAMetalLayer drawable there is no render output shown on the screen. Tests show, that the CAMetalLayer drawable does have a proper texture (with desired size) and the data is written to it as expected, but not shown on screen.
To my surprise running the CAMetalLayer initialization on the main thread fixes this problem. So the following is a solution:
DispatchQueue.global().async {
var renderLayer: CAMetalLayer!
DispatchQueue.main.sync {
renderLayer = CAMetalLayer()
}
renderLayer.isOpaque = false
renderLayer.frame = frame
renderLayer.drawableSize = drawableSize
renderLayer.framebufferOnly = false
renderLayer.device = metalDevice
renderLayer.pixelFormat = metalPixelFormat
renderLayer.contentsScale = contentScale
DispatchQueue.main.async {
view.layer.addSublayer(renderLayer)
}
}
As I want to be able to run the CAMetalLayer creation completely on the background thread I would like to avoid calling CAMetalLayer() on the main thread. Also, I couldn't find any requirement for CAMetalLayer to be initialized on the main thread in the documentation.
So my questions are:
- Is it possible to run the init
CAMetalLayer()on a background thread and if so how? - If it is not possible: why?
Additional Info: I am using XCode 11 and running the code on iOS 13.1. I also had the same issue with XCode 10 and iOS version 12.