【问题标题】:Metal Shading Language - (Console) Output?金属着色语言 - (控制台)输出?
【发布时间】:2016-06-29 08:41:48
【问题描述】:

我可以使用控制台输出(如 Swift 中的 print)调试我的金属着色语言代码吗?

如果是,怎么做?

如果没有,还有其他方法可以从我的 .metal 文件中输出变量吗? (也许通过使用 commandEncoder-buffer 将数据从 .metal 文件传递​​到我的 .swift 文件?)

我尝试通过 commandEncoder 将对 Int 变量(位于我的 .swift 文件中)的引用传递给我的 .metal 文件,但未成功。在 .metal 文件中,我为 int 变量赋值,但如果我在我的 swift 文件中打印 Int,则赋值不存在。

.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

【问题讨论】:

    标签: ios metal console-output


    【解决方案1】:

    如果有人需要,这里有一个可行的解决方案:

    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;
    
    }
    

    【讨论】:

      【解决方案2】:

      这里有几个问题。首先,newBufferWithBytes(_:length:) 对您提供的数据进行副本,因此写入的地址不是原始变量的地址。其次,您似乎没有在尝试读取结果之前等待计算内核完成。您可以在相应的命令缓冲区(阻塞当前线程)上调用waitUntilCompleted(),也可以调用addCompletedHandler() 来提供一个闭包,该闭包将在内核完成运行时异步调用。此时,您应该能够从缓冲区中读回数据。

      没有从金属着色器中打印到命令行的工具,因此写入缓冲区或纹理几乎是您最好的选择。

      【讨论】:

      • 这个答案不完整。您只说使用newBufferWithBytes 是错误的,但不要写改用什么。答案可能是newBufferWithBytesNoCopy,但这仍然不能解决问题,我正在尝试使用它和addCompletedHandler 返回要打印的值,但它仍在打印0。
      • 看来 OP 认为这个答案是完整的,因为它被接受了。听起来您的用例可能略有不同,您可能应该为此提出一个新问题。
      • 我有完全相同的用例,打开一个新问题会被标记为重复,所以我认为问题出在这个答案中。
      • stackoverflow.com/help/accepted-answer "接受答案并不意味着表明问题已经得到完美回答"
      • 如何创建缓冲区并不重要。关键在于语句“[在命令缓冲区完成后],您应该能够在缓冲区的 contents() 上使用 bindMemory 之类的东西从缓冲区读回数据”。
      猜你喜欢
      • 1970-01-01
      • 2017-09-14
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 2012-03-14
      相关资源
      最近更新 更多