跨多个MTKView共享MTLCommandBuffer

时间:2018-07-23 09:02:03

标签: ios swift xcode graphics metal

我正在将MTKViews用于UIKit应用程序内的选定UI元素。我有一个中央金属控制器,其功能类似于以下内容:

public class MetalView: MTKView                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   {

    var id:Int? = nil
    func getBuffer() -> MTLCommandBuffer {
        if (id == nil) {
            id = MetalView.idCounter
            MetalView.idCounter += 1
            MetalView.frameRegistry.append(id!)
            setNeedsDisplay()
        }

        if MetalView.frameRegistry.contains(id!) {
            MetalView.frameRegistry.removeAll()
            if let buffer = MetalView.savedBuffer {
                buffer.commit()
                buffer.waitUntilCompleted()
            }
            MetalView.savedBuffer = MetalView.queue.makeCommandBuffer()
        }
        MetalView.frameRegistry.append(id!)
        return MetalView.savedBuffer!
    }

    static private var savedBuffer:MTLCommandBuffer? = nil
    static private var frameRegistry:[Int] = []
    static private var idCounter:Int = 0

}

每个金属UI元素子类都有自己的ID,允许其在其draw函数中调用getBuffer来获取框架的命令缓冲区。

此代码基于两个假设

  1. 每个MTKView都有自己的可绘制对象
  2. 每帧只能创建一个MTLCommandBuffer

这就是我理解工作原理的方式。

不幸的是,这会导致纹理出现明显的同步错误

enter image description here

这应该是均匀色调的梯度,但是色调被快速切换,结果,这种撕裂留下了一部分,而另一部分的色调不同。

所以我想我的问题是:

  1. 我的假设正确吗
  2. 当并非所有金属绘图对象都需要绘制每一帧时,正确的共享MTLCommandBuffer的方法是什么。
  3. 如何解决此问题?

1 个答案:

答案 0 :(得分:0)

Apple明确声明MTLCommandBuffer只能使用一次,并且一旦提交就不应重复使用。来自《金属编程指南》:

  

命令缓冲区是临时的一次性对象,不支持重用。提交命令缓冲区以供执行后,唯一有效的操作是等待命令缓冲区被调度或完成。

因此,不支持您在做什么。唯一允许重用的对象是:

  • 命令队列
  • 数据缓冲区
  • 纹理
  • 采样器状态
  • 图书馆
  • 计算状态
  • 渲染管道状态
  • 深度/模具状态

来源:Metal Programming Guide

一种可能的解决方案是通过同一Command Queue在每个可绘制对象中排队一个MTLCommandBuffer。要了解如何使两个不同的命令缓冲区入队并确保它们执行的顺序,您应该检查Apple的ObjectExample示例代码。您可以从here下载它。