ios - MTL缓冲区分配+CPU/GPU同步

标签 ios metal metalkit metal-performance-shaders mtlbuffer

我正在使用 Metal 性能着色器( MPSImageHistogram )来计算 MTLBuffer 中的某些内容我抓取、执行计算,然后通过 MTKView 显示。 MTLBuffer着色器的输出很小(~4K 字节)。所以我分配一个新的 MTLBuffer每个渲染 channel 的对象,并且每个视频帧每秒至少有 30 次渲染。

calculation = MPSImageHistogram(device: device, histogramInfo: &histogramInfo)
let bufferLength = calculation.histogramSize(forSourceFormat: MTLPixelFormat.bgra8Unorm)
let buffer = device.makeBuffer(length: bufferLength, options: .storageModeShared)
let commandBuffer = commandQueue?.makeCommandBuffer()

calculation.encode(to: commandBuffer!, sourceTexture: metalTexture!, histogram: buffer!, histogramOffset: 0)
commandBuffer?.commit()

commandBuffer?.addCompletedHandler({ (cmdBuffer) in
    let dataPtr = buffer!.contents().assumingMemoryBound(to: UInt32.self)
    ...
    ...

}

我的问题 -

  1. 每次使用device.makeBuffer(..)创建一个新的缓冲区可以吗? ,或者更好地静态分配 很少的缓冲区并实现重用这些缓冲区?如果重用更好,我们如何同步这些缓冲区上的 CPU/GPU 数据写入/读取?

  2. 另一个不相关的问题,可以画入MTKView吗?非主线程上的结果?或MTKView绘制必须仅在主线程中(即使我读到 Metal 是真正的多线程)?

最佳答案

  1. 分配有点昂贵,因此我建议使用可重用的缓冲区方案。我首选的方法是保留一个可变的缓冲区数组(队列),当使用它的命令缓冲区完成时(或者在您的情况下,在 CPU 上读回结果之后)将缓冲区排入队列,然后分配当队列为空并且需要编码更多工作时使用新缓冲区。在稳定状态下,假设您的帧及时完成,您会发现此方案很少会分配超过 2-3 个缓冲区。如果您需要此方案是线程安全的,则可以使用互斥体(使用 dispatch_semaphore 实现)保护对队列的访问。

  2. 只要遵循标准的多线程预防措施,您就可以使用另一个线程对渲染工作进行编码,将其绘制到由 MTKView 提供的可绘制对象中。请记住,虽然命令队列是线程安全的(从某种意义上说,您可以同时从同一队列创建和编码多个命令缓冲区),但命令缓冲区本身和编码器却不是。我建议您分析单线程情况,并且仅在绝对必要时才引入多线程的复杂性。

关于ios - MTL缓冲区分配+CPU/GPU同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50213499/

相关文章:

ios - CVMetalTextureCacheCreateTextureFromImage 总是返回 null

ios - 由于 API 滥用,CoreBluetooth 正在与未使用的外围设备断开连接

ios - 何时使用 SQLite.swift 将记录提交到磁盘?

ios - 强制 subview Controller 调用基本 View Controller 方法

ios - segueForUnwindingToViewController 导致 "Warning: Attempt to present <...> on <...> which is already presenting <...>"

objective-c - VNSequenceRequestHandler 上的 EXC_BAD_ACCESS

ios - 未找到 Metal 内核函数

ios - 离屏渲染

3d - 计算 3d 中两个向量之间的角度

ios - 使用 Mesh 在 Metal 中绘图