macos - 是否需要在主线程上绘制到 MTKView 或 CAMetalLayer?
问题描述
众所周知,更新用户界面AppKit
或UIKit
需要在主线程上进行。Metal 在展示 时是否有相同的要求drawable
?
在我一直在玩的一个托管层中NSView
,我注意到我可以[CAMetalLayer nextDrawable]
从一个dispatch_queue
不是main_queue
. 然后我可以像往常一样更新该drawable的纹理并呈现它。
这似乎工作正常,但我觉得这很可疑。除非我忽略了文档中的某些内容,否则我找不到任何提及 Metal 的主线程要求(支持或反对)。
(我正在 macOS 10.13 上进行测试,但我认为 iOS 的主线程要求也相同......?)
解决方案
在后台线程上绘制是安全的。文档-nextDrawable
说:
调用此方法会阻塞当前 CPU 线程,直到有新的可绘制对象可用。
(强调。)如果它只能在主线程上调用,那可能不会那么概括。此外,Apple 的一般建议是避免阻塞主线程,所以你会认为他们会在这里以某种方式指出这个事实,例如建议你不要调用它,除非你很确定它不会阻塞。
关于如何使用drawable(而不是获取),请注意一个典型的用例是调用命令缓冲区的-presentDrawable:
方法。该方法便于添加调度的处理程序块(如 via -addScheduledHandler:
),该处理程序块随后将调用-present
可绘制对象。未指定将在哪个线程或队列上调用处理程序块,这表明-present
对可绘制对象的调用不会发生在主线程上。
甚至在那之后,drawable 在屏幕上的实际呈现在对-present
. 可绘制对象等待直到渲染或写入其纹理的任何命令完成,然后才呈现到屏幕上。没有具体说明如何实现这种异步性,但它进一步表明-present
调用哪个线程并不重要。
Metal Programming Guide中有一些关于多线程的讨论,尽管它并不像人们希望的那样直接。请特别参阅多线程、命令缓冲区和命令编码器部分。请注意,这里讨论了由后台线程填充的命令缓冲区,并且没有关于使用可绘制对象的具体警告。同样,这是一种缺乏证据的论点,但我认为这很清楚。他们确实呼吁一次只能有一个线程对给定的命令缓冲区进行操作,因此他们正在考虑线程安全问题。