Metal Shading Language - (Консоль) Выход?

Могу ли я отладить свой код языка металлического шейдинга с помощью вывода на консоль (например, print в Свифт)?

Если да, то как?

Если нет, есть ли другие способы вывода переменных из моего файла.metal? (Может быть, передавая данные из файла.metal в мой файл.swift, используя команду Encoder-buffer?)

Я безуспешно пытался передать ссылку на переменную Int (которая находится в моем файле.swift) через команду Encoder в мой файл.metal. В файле.metal я присваиваю значение переменной int, но если я печатаю Int в моем файле swift, назначенного значения там нет.

.swift файл:

...
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:

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

Консольный вывод всегда myMetalOutput: 0

2 ответа

Решение

Вот рабочее решение на тот случай, если кому-то это нужно:

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 ")
}

Шейдер:

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

    printBuffer = 123;

}

Есть несколько вещей, которые идут не так, как надо здесь. Первый, newBufferWithBytes(_:length:) создает копию предоставленных вами данных, поэтому адрес, на который записывается, не является адресом исходной переменной. Во-вторых, вы, похоже, не дожидаетесь завершения вычислительного ядра, прежде чем пытаетесь прочитать результат. Вы можете позвонить waitUntilCompleted() в соответствующем буфере команд (который блокирует текущий поток), или вы можете вызвать addCompletedHandler() обеспечить замыкание, которое будет вызываться асинхронно после завершения работы ядра. В этот момент вы сможете читать данные из буфера.

Нет возможности печатать в командную строку из металлического шейдера, поэтому запись в буфер или текстуру - ваш лучший выбор.

Другие вопросы по тегам