【问题标题】:Combine multiple MTKView/CAMetalLayer display组合多个MTKView/CAMetalLayer显示
【发布时间】:2018-11-12 07:55:50
【问题描述】:

我正在使用多个 MTKViews 在屏幕上显示不同的内容以及普通的 UIView(用于显示 UI)。我想将这些 MTKViews 的呈现与同一个时钟同步。有没有办法同步这些 MTKViews 的呈现?原则上,我可以将这些视图的布局组合到一个 MTKView 中,但这会破坏代码的模块化,并且不确定我是否会在过度工作的情况下实现任何性能。

【问题讨论】:

  • 如何同步它们,究竟是什么?您是否希望它们具有固定的帧速率(例如 60 fps)?您是否希望它们以可变帧速率全部绘制在一起(它们都在最慢完成后立即渲染)?或者您是否考虑过其他系统,例如如果其中一个足够慢,它会跳过其他可能绘制的帧,但确实绘制的那些会一起这样做,并且当慢的一个可以时,它会参与该同步?
  • 我想以固定的帧速率绘制它们,所有这些都与同一个时钟同步。

标签: ios metal metalkit


【解决方案1】:

一种在大多数情况下都适用的简单方法是计算您希望绘制框架的时间,并使用MTLCommandBufferpresent(_:atTime:) 方法而不是present(_:) 方法。


为了进行更大的控制,了解命令缓冲区的present... 方法做什么和不做什么会有所帮助。他们确实将任何命令编码到缓冲区中。如文档所述,他们基本上只是为自己添加了一个调度处理程序,该处理程序在可绘制对象上调用 present

如果你对此很小心,你可以安排以一种不涉及命令缓冲区的方式呈现可绘制对象。

但是,使用 scheduled 处理程序的命令缓冲区有意义吗?它不应该使用 completed 处理程序吗?毕竟,你要显示完成的渲染,对吧?

好吧,drawables 很聪明地展示自己。 present 方法不会立即出现。一个可绘制的轨道,预定的命令可能会渲染或写入其纹理。当present 被调用时,它会安排可绘制对象尽快在屏幕上绘制自己在所有此类命令完成后。 (请注意,这并不意味着命令缓冲区本身已完成。可能还有其他不涉及可绘制对象纹理的命令尚未完成。)

这为同步多个可绘制对象的呈现提供了挑战和机遇。挑战在于,虽然您可以控制在每个可绘制对象上调用 present 的时间,但这并不一定会同步它们的实际显示,因为在调用 present 并且所有涉及其纹理的命令之后,每个都将尽快显示已完成,并且对于不同的可绘制对象,最后一部分可以在不同的时间发生。

解决此问题的一种可能方法是将呈现的处理程序添加到主可绘制对象。处理程序将在其他 3 个可绘制对象上调用 present。在调度所有命令缓冲区后,在主可绘制对象上调用 present。您可以使用调度组来确定何时调度所有命令缓冲区。为每个命令缓冲区输入一次组,并为每个离开该组的处理程序添加一个预定的处理程序。然后在 master 存在的组上设置一个通知块。这种技术可能无法实现完美的同步,因为在主可绘制对象实际呈现和所呈现的处理程序被调用之间存在延迟,然后在呈现其他可绘制对象时存在延迟。

另一种可能的方法是将所有CAMetalLayers 的presentsWithTransaction 属性设置为true。然后,在展示的时候,在每个命令缓冲区上调用waitUntilScheduled,然后在每个可绘制对象上调用present。 (不要使用命令缓冲区的present... 方法。)这将保证所有可绘制对象都将出现在同一个核心动画事务中——即同步。

【讨论】:

  • 但是单个MTLCommandBuffer可以用来呈现4个不同的MTKViews/CAMetalLayer吗?
  • 可以,但我的建议与此无关。您可以使用四个不同的命令缓冲区并让它们同时存在。关键是 API 让您可以控制何时呈现可绘制对象,这是您可以用来同步它们的工具。
  • 有趣,但 present(_:atTime:) 有问题。我想将剩余的 3 个视图与 master 的演示文稿(即视频预览)同步。我知道我可以将视频预览延迟 30 毫秒,然后使用 _atTime: 显示所有内容,这不会引起注意,但原则上是否可以将剩余视图与一个视图同步?
【解决方案2】:

你可以使用 PresentWithTransaction

  1. 在 MTKView 中设置 presentWithTransaction = true

  2. 更改 commandBuffer 提交样式

     public func draw(in view: MTKView) {
    
     ...
    
     commandBuffer?.commit()
     commandBuffer?.waitUntilScheduled()
     view.currentDrawable?.present() }
    

现在所有金属视图将同步显示。 它对我有用。

【讨论】:

    猜你喜欢
    • 2021-11-25
    • 2019-12-24
    • 1970-01-01
    • 2019-01-19
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-30
    相关资源
    最近更新 更多