Search code examples
iosmetalconsole-output

Metal Shading Language - (Console) Output?


Can I debug my metal-shading-language code using console output (like print in Swift)?

If yes, how?

If no, are there any other ways to output variables from my .metal file? (Maybe by passing data from the .metal file to my .swift file using the commandEncoder-buffer?)

I have unsuccessfully tried to pass a reference to an Int variable (which is in my .swift file) via the commandEncoder to my .metal file. In the .metal file, I assign a value to the int variable, but if I print the Int in my swift file, the assigned value is not there.

.swift file:

...
var myMetalOutput: Int = 0
...
let printBuffer = device.newBufferWithBytes(&myMetalOutput, length: sizeof(Int), options: MTLResourceOptions.CPUCacheModeDefaultCache)
commandEncoder.setBuffer(printBuffer, offset: 0, atIndex: 8)
...
commandBuffer.commit()
drawable.present()
print("myMetalOutput: \(myMetalOutput)")
...

.metal file:

...
kernel void shader(..., device int &printBuffer [[8]], ...) {
...
printBuffer = 123;
...
}

The console output is always myMetalOutput: 0


Solution

  • Here's a working solution in case somebody needs it:

    let device = MTLCreateSystemDefaultDevice()!
    let commandQueue = device.newCommandQueue()
    let defaultLibrary = device.newDefaultLibrary()!
    let commandBuffer = commandQueue.commandBuffer()
    let computeCommandEncoder = commandBuffer.computeCommandEncoder()
    
    let program = defaultLibrary.newFunctionWithName("shader")
    
    do
    {
        let computePipelineFilter = try device.newComputePipelineStateWithFunction(program!)
        computeCommandEncoder.setComputePipelineState(computePipelineFilter)
        var resultdata = [Int](count: 1, repeatedValue: 0)
        let outVectorBuffer = device.newBufferWithBytes(&resultdata, length: sizeofValue(1), options: MTLResourceOptions.CPUCacheModeDefaultCache)
        computeCommandEncoder.setBuffer(outVectorBuffer, offset: 0, atIndex: 0)
    
    
        let threadsPerGroup = MTLSize(width:1,height:1,depth:1)
        let numThreadgroups = MTLSize(width:1, height:1, depth:1)
        computeCommandEncoder.dispatchThreadgroups(numThreadgroups, threadsPerThreadgroup: threadsPerGroup)
    
    
        computeCommandEncoder.endEncoding()
    
        commandBuffer.addCompletedHandler {commandBuffer in
            let data = NSData(bytes: outVectorBuffer.contents(), length: sizeof(NSInteger))
            var out: NSInteger = 0
            data.getBytes(&out, length: sizeof(NSInteger))
            print("data: \(out)")
        }
    
        commandBuffer.commit()
    
    }
    catch
    {
        fatalError("newComputePipelineStateWithFunction failed ")
    }
    

    The shader:

    kernel void shader(device int &printBuffer [[buffer(0)]], uint id [[ thread_position_in_grid ]]) {
    
        printBuffer = 123;
    
    }