我正在使用多个 MTKViews 在屏幕上显示不同的内容以及普通的 UIView(用于显示 UI)。我想将这些 MTKViews 的呈现与同一个时钟同步。有没有办法同步这些 MTKViews 的呈现?原则上,我可以将这些视图的布局组合到一个 MTKView 中,但这会破坏代码的模块化,并且不确定我是否会在过度工作的情况下实现任何性能。
2 回答
在大多数情况下应该工作的简单方法是计算您希望绘制框架的时间并使用present(_:atTime:)
方法MTLCommandBuffer
而不是present(_:)
方法。
为了施加更大的控制,它有助于理解命令缓冲区的present...
方法做什么和不做什么。它们不会将任何命令编码到缓冲区中。如文件所述,他们基本上只是为自己添加了一个调用present
可绘制对象的调度处理程序。
如果您对此很小心,您可以安排以不涉及命令缓冲区的方式呈现可绘制对象。
但是,使用预定处理程序的命令缓冲区有意义吗?它不应该使用已完成的处理程序吗?毕竟,你想要显示完成的渲染,对吧?
好吧,drawables 很聪明地展示自己。该present
方法不会立即出现。一个可绘制的轨道,预定的命令可能会渲染或写入其纹理。当被调用时,它会安排可绘制对象在所有此类命令完成后present
尽快在屏幕上绘制自己。(请注意,这并不意味着命令缓冲区本身已经完成。可能还有其他不涉及可绘制对象纹理的命令尚未完成。)
这为同步多个可绘制对象的呈现提供了挑战和机遇。挑战在于,虽然您可以控制何时调用present
每个可绘制对象,但这并不一定会同步它们的实际显示,因为每个可在present
调用后尽快显示并且涉及其纹理的所有命令都已完成,最后一部分对于不同的drawable,可以在不同的时间发生。
解决此问题的一种可能方法是将呈现的处理程序添加到主可绘制对象。处理程序将调用present
其他 3 个可绘制对象。在安排好所有命令缓冲区后,调用present
主可绘制对象。您可以使用调度组来确定何时调度所有命令缓冲区。为每个命令缓冲区输入一次组,并为每个离开该组的处理程序添加一个预定的处理程序。然后在 master 存在的组上设置一个通知块。这种技术可能无法实现完美的同步,因为在主可绘制对象实际呈现和调用所呈现的处理程序之间存在延迟,然后在呈现其他可绘制对象时存在延迟。
另一种可能的方法是将presentsWithTransaction
所有 s 的属性设置CAMetalLayer
为 true。然后,在展示的时候,调用waitUntilScheduled
每个命令缓冲区,然后调用present
每个可绘制对象。(不要使用present...
命令缓冲区的方法。)这将保证所有可绘制对象都将出现在同一个核心动画事务中 - 即同步。
您可以使用 PresentWithTransaction
在 MTKView 中设置 presentWithTransaction = true
更改 commandBuffer 提交样式
public func draw(in view: MTKView) { ... commandBuffer?.commit() commandBuffer?.waitUntilScheduled() view.currentDrawable?.present() }
现在所有金属视图将同步显示。这个对我有用。