是否需要在主线程上绘制到 MTKView 或 CAMetalLayer?

Is drawing to an MTKView or CAMetalLayer required to take place on the main thread?

众所周知,在 AppKitUIKit 中更新用户界面需要在主线程上进行。 Metal 在呈现 drawable 时是否有相同的要求?

在我一直玩弄的层托管 NSView 中,我注意到我可以从 dispatch_queue 调用 [CAMetalLayer nextDrawable] 而不是 main_queue。然后我可以像往常一样更新该可绘制对象的纹理并呈现它。

似乎 可以正常工作,但我觉得这很可疑。除非我忽略了文档中的某些内容,否则我找不到任何提及 Metal 的主线程要求(支持或反对)。

(我正在 macOS 10.13 上进行测试,但我假设 iOS 的主线程要求也相同......?)

在后台线程上绘制是安全的。 docs for -nextDrawable 说:

Calling this method blocks the current CPU thread until a new drawable is available.

(重点加了。)如果只能在主线程调用,那估计就没那么泛化了。此外,Apple 的一般建议是避免阻塞主线程,因此您认为他们会在这里以某种方式指出这一事实,例如建议您不要调用它,除非您非常确定它不会阻塞。

关于可绘制对象的使用方式(而不是获取方式),请注意典型的用例是调用命令缓冲区的 -presentDrawable: 方法。该方法便于添加预定的处理程序块(如通过 -addScheduledHandler:),该处理程序块随后将在可绘制对象上调用 -present。未指定处理程序块将在哪个线程或队列上调用,这表明无法保证对可绘制对象的 -present 调用将在主线程上发生。

即使在那之后,可绘制对象在屏幕上的实际呈现在对 -present 的调用中也不是同步的。可绘制对象会等待渲染或写入其纹理的任何命令完成,然后才显示在屏幕上。它没有具体说明异步性是如何实现的,但它进一步表明调用哪个线程 -present 并不重要。

Metal Programming Guide, although it's not quite as direct as one might hope. See especially the section on Multiple Threads, Command Buffers, and Command Encoders 中有一些关于多线程的讨论。请注意,这里讨论了由后台线程填充的命令缓冲区,并且没有关于使用可绘制对象的具体警告。同样,这是一种缺乏证据的争论,但我认为这很清楚。他们确实指出,一次只能有一个线程作用于给定的命令缓冲区,因此他们正在考虑线程安全问题。