I am trying to setup and execute a compute kernel and submit it's output to MTKView to draw. But I get the following crash:
-[MTLDebugCommandBuffer computeCommandEncoder]:889: failed assertion `encoding in progress'
What is wrong with the code below? Is feeding the output of compute shader to render pipeline not supported using the same commandBuffer?
func computeKernel(_ texture:MTLTexture, commandBuffer:MTLCommandBuffer) {
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
computeEncoder?.setComputePipelineState(computePipelineState!)
computeEncoder?.setTexture(texture, index: 0)
computeEncoder?.setTexture(texture, index: 1)
computeEncoder?.dispatchThreadgroups(threadgroupCount, threadsPerThreadgroup: threadgroupSize)
computeEncoder?.endEncoding()
/*
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
*/
}
override func draw(_ rect: CGRect) {
guard let drawable = currentDrawable,
let currentRenderPassDescriptor = currentRenderPassDescriptor
else {
return
}
// Set up command buffer and encoder
guard let commandQueue = commandQueue else {
print("Failed to create Metal command queue")
return
}
guard let commandBuffer = commandQueue.makeCommandBuffer() else {
print("Failed to create Metal command buffer")
return
}
guard let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: currentRenderPassDescriptor) else {
print("Failed to create Metal command encoder")
return
}
commandEncoder.label = "Preview display"
let texture = ... //Grab a Metal texture
computeKernel(texture, commandBuffer: commandBuffer)
commandEncoder.setRenderPipelineState(defaultRenderPipelineState!)
commandEncoder.setFragmentTexture(texture, index: 0)
commandEncoder.setVertexBytes(vertices, length: vertices.count * MemoryLayout<AAPLVertex>.stride, index: 0)
commandEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
commandEncoder.endEncoding()
commandBuffer.present(drawable) // Draw to the screen
commandBuffer.commit()
}
You can encode compute and render work into the same command buffer, but you can't start another command encoder while an existing command encoder is encoding. In your case, you create the render command encoder, then call a function that creates a compute command encoder without ending the render command encoder. Instead, you should call your compute function, then create and use your render command encoder.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With