我确实有一个直接的 CAMetalLayer 设置,除了 CAMetalLayer 是在全局线程上初始化的,如下所示(调用 init,设置基本属性并添加为子层):
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)
}
}
此代码运行时没有任何运行时错误,但不幸的是,当渲染到
CAMetalLayer
可绘制对象时,屏幕上没有显示渲染输出。测试表明,CAMetalLayer
可绘制对象确实具有适当的纹理(具有所需的大小),并且数据按预期写入其中,但未显示在屏幕上。
令我惊讶的是,在主线程上运行
CAMetalLayer
初始化修复了这个问题。所以解决办法如下:
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)
}
}
因为我希望能够完全在后台线程上运行
CAMetalLayer
创建,所以我想避免在主线程上调用CAMetalLayer()
。另外,我在文档中找不到在主线程上初始化 CAMetalLayer
的任何要求。
所以我的问题是:
CAMetalLayer()
,如果可以的话如何运行?其他信息:我正在使用 XCode 11 并在 iOS 13.1 上运行代码。我在 XCode 10 和 iOS 版本 12 上也遇到了同样的问题。
-[CAMetalLayer init]
需要在 CA 渲染器循环上注册观察者并接收回调以完成初始化。但是,使用 DispatchQueue.global()
意味着无法保证何时调用回调,从而导致 CAMetalLayer 等待并阻止任何绘图发生。如果您需要在后台线程上初始化 CAMetalLayer,请改用 NSThread。
__block CAMetalLayer *metalLayer = [CAMetalLayer new];;
dispatch_semaphore_t s = dispatch_semaphore_create(0);
NSThread *t = [[NSThread alloc] initWithBlock:^{
metalLayer = [CAMetalLayer new];
dispatch_semaphore_signal(s);
}];
[t start];
dispatch_semaphore_wait(s, DISPATCH_TIME_FOREVER);
dispatch_release(s);
[t release];