【发布时间】:2018-07-13 17:33:14
【问题描述】:
我正在使用 Metal Programming Guide 一书为 iOS 开发一个简单的 Metal 程序,但 makeBuffer(bytes:length:options:) 并没有像书中所述那样工作。
相关代码如下
let vertexData: [Float] = [
0.0, 0.5, 0.0,
-1.0, -0.5, 0.0,
1.0, -0.5, 0.0
]
let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0])
vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize,
options: [.storageModePrivate]) // error on this line
...
let renderEncoder = commandBuffer?.makeRenderCommandEncoder(
descriptor: renderPassDescriptor)
renderEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
// skipping other setups
renderEncoder?.endEncoding()
在运行时会导致崩溃,这里是错误日志:
-[MTLDebugDevice newBufferWithBytes:length:options:]:494: failed assertion `storageModePrivate incompatible with ...WithBytes variant of newBuffer'
但是,如果我在makeBuffer(bytes:length:options:) 中使用[] 作为options 的参数,则程序可以正常工作:
vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize,
options: []) // this will run
但是为什么会这样呢?
【问题讨论】:
-
私有存储模式用于仅可由 GPU 访问的内存。在这种情况下,我不确定为什么会出错,因为
makeBuffer(bytes:...)应该复制数据。在任何情况下,makeBuffer(bytes:)的文档都明确表示此处不允许使用私有存储模式。 -
它 so “只能由 GPU 访问”,CPU 甚至无法用初始数据填充它。它必须用数据创建一个临时的非私有缓冲区,创建私有缓冲区,创建命令队列,创建命令缓冲区,对命令进行编码以从一个缓冲区复制到另一个缓冲区,提交命令缓冲区,释放临时缓冲区,并等待命令缓冲区完成。 Metal 的理念是 API 不会在你背后做令人惊讶的事情。所以,你必须自己做。
-
@KenThomases 我试图按照stackoverflow.com/questions/51159795/… 的答案,但找不到将Objective-C 代码转换为Swift 的正确方法。您能否更具体地说明如何在 Swift 中实现这一目标?谢谢!