我正在嘗試使用MTLSharedEventwithMTLSharedEventListener來同步 GPU 和 CPU 之間的計算,如 Apple 提供的示例(https://developer.apple.com/documentation/metal/synchronization/synchronizing_events_between_a_gpu_and_the_cpu)。基本上我想要實作的是將作業分為三個部分按順序執行,如下所示:
- GPU 計算第 1 部分
- 基于 GPU 計算第 1 部分結果的 CPU 計算
- CPU 計算后的 GPU 計算第 2 部分
我的問題是eventListener在計劃執行命令緩沖區之前總是呼叫塊,這使我的 CPU 任務按順序執行。
為了簡化案例,讓我們使用填充MTLBuffer某些值的簡單命令(我的原始用例更復雜,因為使用帶有自定義著色器的計算編碼器,但行為相同):
let device = MTLCreateSystemDefaultDevice()!
let queue = device.makeCommandQueue()!
let event = device.makeSharedEvent()!
let dispatchQueue = DispatchQueue(label: "myqueue")
let eventListener = MTLSharedEventListener(dispatchQueue: dispatchQueue)
let metalBuffer = device.makeBuffer(length: 2048, options: MTLResourceOptions.storageModeShared)!
let buffer = queue.makeCommandBuffer()!
NSLog("Start - signaled value: \(event.signaledValue)")
event.notify(eventListener, atValue: 1) { event, value in
// CPU work
let pointer = metalBuffer.contents().assumingMemoryBound(to: UInt8.self)
for i in 0..<512 {
(pointer i).pointee = (pointer i).pointee 1;
}
NSLog("Event notification - signaled value: \(value), buffer status: \(buffer.status.rawValue)")
event.signaledValue = 2
}
// GPU work part 1
let encoder1 = buffer.makeBlitCommandEncoder()!
encoder1.fill(buffer: metalBuffer, range: .init(0...127), value: 22)
encoder1.endEncoding()
// signal with 1 to start CPU task
buffer.encodeSignalEvent(event, value: 1)
// wait for value >= 2 to proceed
buffer.encodeWaitForEvent(event, value: 2)
// GPU work part 2
let encoder2 = buffer.makeBlitCommandEncoder()!
encoder2.fill(buffer: metalBuffer, range: .init(128...511), value: 255)
encoder2.endEncoding()
buffer.addScheduledHandler { buffer in
NSLog("Buffer scheduled - signaled value: \(event.signaledValue)")
}
buffer.addCompletedHandler { buffer in
NSLog("Buffer completed - signaled value: \(event.signaledValue)")
}
buffer.commit()
buffer.waitUntilCompleted()
輸出:
2022-01-09 23:46:08.774 Sync[76882:3531755] Metal GPU Frame Capture Enabled
2022-01-09 23:46:08.805 Sync[76882:3531755] Start - signaled value: 0
2022-01-09 23:46:08.808 Sync[76882:3531764] Event notification - signaled value: 1, buffer status: 2 (Commited)
2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer scheduled - signaled value: 2
2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer completed - signaled value: 2
如您所見,eventListener日志緩沖區狀態為.commited. 這是怎么回事?我錯過了什么嗎?
系統:macOS 12.0.1、Apple M1 Pro、Xcode 13.2.1
uj5u.com熱心網友回復:
提交命令緩沖區非常好。實際上,如果不提交,您將永遠無法notify阻止。
GPU 和 CPU 并行運行。因此,當您使用時,您MTLEvent不會停止執行 CPU 代碼(實際上是所有 Swift 代碼)。您只需告訴 GPU 以什么順序執行 GPU 代碼。
那么在你的情況下發生了什么:
- 您的所有代碼都在單個 CPU 執行緒中運行而不會中斷。
- GPU 僅在您呼叫
commit(). 在它之前GPU實際上什么都不做。您剛剛安排了要在 GPU 上執行的命令,但不執行它們。 - 當 GPU 執行命令時,它會檢查您的
MTLEvent. 它執行第 1 部分,然后將值編碼1為事件,執行通知塊,編碼值2,執行第二個 GPU 塊。
但同樣,所有實際的 GPU 作業僅在您呼叫commit()命令緩沖區時才開始。這就是為什么緩沖區已經在通知塊中提交的原因。因為它是在 之后執行的commit()。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/409423.html
標籤:
