2016-03-14 23 views
6

Czy mogę debugować mój kod języka cieniowania przy użyciu wyjścia konsoli (np. print w Swift)?Metal Shading Language - (Console) Output?

Jeśli tak, w jaki sposób?

Jeśli nie, czy istnieją inne sposoby wyprowadzania zmiennych z mojego pliku .metal? (Może przekazując dane z pliku .metal do mojego pliku .swift przy użyciu poleceniaEncoder-buffer?)

Bezskutecznie próbowałem przekazać odwołanie do zmiennej Int (która znajduje się w moim pliku .swift) za pomocą poleceniaEncoder do mojego pliku .metal. W pliku .metal przypisuję wartość do zmiennej int, ale jeśli wydrukuję Int w moim pliku swift, przypisana wartość nie istnieje.

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

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

Wyjście konsola jest zawsze myMetalOutput: 0

Odpowiedz

1

Oto rozwiązanie działa w przypadku ktoś musi go:

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

Shader:

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

    printBuffer = 123; 

} 
1

Istnieje kilka rzeczy nie tak tutaj. Najpierw newBufferWithBytes(_:length:) podaje dane, które podasz, więc adres, na który zapisano, nie jest adresem oryginalnej zmiennej. Po drugie, nie wydajesz się czekać na zakończenie jądra obliczeniowego przed próbą odczytania wyniku. Możesz zadzwonić pod numer waitUntilCompleted() w odpowiednim buforze poleceń (który blokuje bieżący wątek) lub możesz zadzwonić pod numer addCompletedHandler(), aby zapewnić zamknięcie, które będzie się nazywać asynchronicznie po zakończeniu działania jądra. W tym momencie powinieneś być w stanie odczytać dane z bufora.

Nie ma możliwości drukowania na linii poleceń z poziomu modułu cieniującego Metal, więc zapisywanie do bufora lub tekstury jest tutaj najlepszą opcją.

+1

Ta odpowiedź nie jest kompletna. Mówisz tylko, że użycie 'newBufferWithBytes' jest niepoprawne, ale nie pisz tego, czego chcesz użyć. Odpowiedź brzmi prawdopodobnie "newBufferWithBytesNoCopy", ale to nadal nie rozwiązuje problemu, próbuję zwrócić wartość do wydrukowania za pomocą tego i 'addCompletedHandler' i nadal drukuje 0. – Ixx

+0

Wygląda na to, że PO uznał tę odpowiedź za kompletną, ze względu na akceptację. Wygląda na to, że możesz mieć nieco inny przypadek użycia, dla którego prawdopodobnie powinieneś otworzyć nowe pytanie. – warrenm

+0

Mam dokładnie taki sam przypadek użycia, otwarcie nowego pytania zostanie oznaczone jako duplikat, więc myślę, że problem leży w tej odpowiedzi. – Ixx