Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Metal makeComputeCommandEncoder assertion failure

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()
}
like image 805
Deepak Sharma Avatar asked May 02 '18 18:05

Deepak Sharma


1 Answers

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.

like image 163
warrenm Avatar answered Sep 21 '22 02:09

warrenm