2016-03-14 14 views
6

È possibile eseguire il debug del codice del linguaggio di ombreggiatura in metallo utilizzando l'output della console (come print in Swift)?Lingua Metal Shading - Uscita (console)?

Se sì, come?

Se no, esistono altri modi per generare variabili dal mio file .metal? (Forse passando i dati dal file .metal al mio file .swift usando il comandoEncoder-buffer?)

Ho tentato senza successo di passare un riferimento a una variabile Int (che si trova nel mio file .swift) tramite il comandoEncoder al mio file .metal. Nel file .metal, assegno un valore alla variabile int, ma se stampo Int nel mio file swift, il valore assegnato non è lì.

file di .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)") 
... 

file di .metal:

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

L'uscita della console è sempre myMetalOutput: 0

risposta

1

Ecco una soluzione di lavoro nel caso in cui qualcuno ne ha bisogno:

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

Lo shader:

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

    printBuffer = 123; 

} 
1

Ci sono un paio di cose che vanno male qui. Innanzitutto, newBufferWithBytes(_:length:) fa una copia copia dei dati forniti, quindi l'indirizzo che viene scritto non è l'indirizzo della variabile originale. In secondo luogo, non sembra che si stia aspettando il completamento del kernel di calcolo prima di tentare di leggere il risultato. È possibile chiamare waitUntilCompleted() nel buffer dei comandi corrispondente (che blocca il thread corrente) oppure chiamare addCompletedHandler() per fornire una chiusura che verrà chiamata in modo asincrono al termine dell'esecuzione del kernel. A quel punto, dovresti essere in grado di leggere i dati dal buffer.

Non è possibile stampare sulla riga di comando da uno shader di metallo, quindi la scrittura su un buffer o texture è praticamente l'opzione migliore qui.

+1

Questa risposta non è completa. Dici solo che l'uso di 'newBufferWithBytes' è sbagliato ma non scrivi cosa usare invece. La risposta è probabilmente 'newBufferWithBytesNoCopy' ma questo ancora non risolve il problema, sto cercando di restituire il valore da stampare usando questo e' addCompletedHandler' e sta ancora stampando 0. – Ixx

+0

Sembrerebbe che l'OP consideri completa questa risposta, a causa di essere accettato. Sembra che tu possa avere un caso d'uso leggermente diverso, per il quale probabilmente dovresti aprire una nuova domanda. – warrenm

+0

Ho esattamente lo stesso caso d'uso, l'apertura di una nuova domanda sarebbe contrassegnata come duplicata, quindi penso che il problema sia in questa risposta. – Ixx