我在我的 UIKit 应用程序中使用 MTKViews 来选择 UI 元素。我有一个中央 Metal Controller ,它做的事情有点像这样:
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
}
每个 Metal UI 元素的子类都有自己的 ID,允许它在其绘制函数中调用 getBuffer 以获取框架的命令缓冲区。
这段代码基于两个假设
- 每个 MTKView 都有自己的 drawable
- 你应该每帧只制作一个 MTLCommandBuffer
这就是我理解事物运作的方式。
不幸的是,这与纹理产生了相当明显的同步错误
这应该是一个均匀色调的渐变,但色调被快速切换,结果留下了撕裂,其中一部分绘制了与另一部分不同的色调。
所以我想我的问题是:
- 我的假设是否正确
- 当并非所有对象都需要绘制每一帧时,跨 Metal 绘图对象共享 MTLCommandBuffer 的正确方法是什么。
- 我该如何解决这个问题?
最佳答案
Apple 明确指出 MTLCommandBuffer 只能使用一次,一旦提交就不应重复使用。来自 Metal 编程指南:
Command buffers are transient single-use objects and do not support reuse. Once a command buffer has been committed for execution, the only valid operations are to wait for the command buffer to be scheduled or completed.
因此,不支持您正在做的事情。唯一允许重用的对象是:
- 命令队列
- 数据缓冲区
- 纹理
- 采样器状态
- 图书馆
- 计算状态
- 渲染管线状态
- 深度/模板状态
您的问题的一个可能解决方案是通过相同的命令队列为每个可绘制对象排队一个 MTLCommandBuffer。要了解如何对两个不同的命令缓冲区进行排队并确保它们的执行顺序,您应该查看 Apple 的 ObjectExample 示例代码。您可以从here下载。 .
关于ios - 跨多个 MTKViews 共享一个 MTLCommandBuffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51475080/