10

I am new to MetalKit and trying to convert this tutorial from playground back to OSX app:

    import MetalKit

public class MetalView: MTKView {

    var queue: MTLCommandQueue! = nil
    var cps: MTLComputePipelineState! = nil

    required public init(coder: NSCoder) {
        super.init(coder: coder)
        device = MTLCreateSystemDefaultDevice()
        registerShaders()
    }


    override public func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)
        if let drawable = currentDrawable {
            let command_buffer = queue.commandBuffer()
            let command_encoder = command_buffer.computeCommandEncoder()
            command_encoder.setComputePipelineState(cps)
            command_encoder.setTexture(drawable.texture, atIndex: 0)
            let threadGroupCount = MTLSizeMake(8, 8, 1)
            let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1)
            command_encoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
            command_encoder.endEncoding()
            command_buffer.presentDrawable(drawable)
            command_buffer.commit()
        }
    }

    func registerShaders() {
        queue = device!.newCommandQueue()
        do {
            let library = device!.newDefaultLibrary()!
            let kernel = library.newFunctionWithName("compute")!
            cps = try device!.newComputePipelineStateWithFunction(kernel)
        } catch let e {
            Swift.print("\(e)")
        }
    }
}

I got an error at the line:

command_encoder.setTexture(drawable.texture, atIndex: 0)

failed assertion `frameBufferOnly texture not supported for compute.'

How can I resolve this?

sooon
  • 4,718
  • 8
  • 63
  • 116

2 Answers2

27

If you want to write to a drawable's texture from a compute function, you'll need to tell the MTKView that it should configure its layer not to be framebuffer-only:

metalView.framebufferOnly = false

With this value set to false, your drawable will give you a texture with the shaderWrite usage flag set, which is required when writing a texture from a shader function.

warrenm
  • 31,094
  • 6
  • 92
  • 116
  • Where should we set this? within the `MetalView` Class? – sooon Aug 29 '16 at 22:30
  • OK, I got it. I set `self.frameBufferOnly = false` and it works. – sooon Aug 29 '16 at 23:32
  • This is strange, I found if I run the code in playground, I don't need to set this line, but If I adopt the code to an App, I need to add this . – XueYu Apr 16 '17 at 18:43
  • I had to put `self.framebufferOnly = false` in the `init`. Setting this in the draw call is too late to avoid the assertion. – raheel Jun 02 '20 at 05:02
0

I have the same issue even I set the frameBufferOnly to false and print the boolean for double check before using the drawable.

But when I turn off the GPU frame capture, no more assertion occurs (for now at least). Still don't know why.

Menu > Scheme > Edit Scheme > Run > Options > GPU Frame Capture: Disabled

Chen OT
  • 3,486
  • 2
  • 24
  • 46