Monday, November 9, 2026
HomeiOS Developmentios - Synchronize work between CPU and GPU inside single command buffer...

ios – Synchronize work between CPU and GPU inside single command buffer utilizing MTLSharedEvent

[ad_1]

I’m attempting to make use of MTLSharedEvent together with MTLSharedEventListener to synchronize computation between GPU and CPU, as in instance supplied by Apple (https://developer.apple.com/documentation/metallic/synchronization/synchronizing_events_between_a_gpu_and_the_cpu). Mainly what I need to obtain is have work break up into 3 elements executed so as, like so:

  1. GPU computation half 1
  2. CPU computation based mostly on outcomes from GPU computation half 1
  3. GPU computation half 2 after CPU computation

My downside is that eventListener block is all the time known as earlier than command buffer is being scheduled for execution, which make my CPU job execute first so as.

To simplify the case, let’s use easy instructions that fill MTLBuffer with sure values (my unique use case is extra sophisticated, as utilizing compute encoders with customized shaders, however behaves the identical):

let gadget = MTLCreateSystemDefaultDevice()!
let queue = gadget.makeCommandQueue()!
let occasion = gadget.makeSharedEvent()!
let dispatchQueue = DispatchQueue(label: "myqueue")
let eventListener = MTLSharedEventListener(dispatchQueue: dispatchQueue)

let metalBuffer = gadget.makeBuffer(size: 2048, choices: MTLResourceOptions.storageModeShared)!

let buffer = queue.makeCommandBuffer()!

NSLog("Begin - signaled worth: (occasion.signaledValue)")

occasion.notify(eventListener, atValue: 1) { occasion, worth in
    // CPU work 
    let pointer = metalBuffer.contents().assumingMemoryBound(to: UInt8.self)
    for i in 0..<512 {
        (pointer + i).pointee = (pointer + i).pointee  + 1;
    }

    NSLog("Occasion notification - signaled worth: (worth), buffer standing: (buffer.standing.rawValue)")
    occasion.signaledValue = 2
}

// GPU work half 1
let encoder1 = buffer.makeBlitCommandEncoder()!
encoder1.fill(buffer: metalBuffer, vary: .init(0...127), worth: 22)
encoder1.endEncoding()

// sign with 1 to start out CPU job 
buffer.encodeSignalEvent(occasion, worth: 1)
// look ahead to worth >= 2 to proceed
buffer.encodeWaitForEvent(occasion, worth: 2)

// GPU work half 2
let encoder2 = buffer.makeBlitCommandEncoder()!
encoder2.fill(buffer: metalBuffer, vary: .init(128...511), worth: 255)
encoder2.endEncoding()

buffer.addScheduledHandler { buffer in
    NSLog("Buffer scheduled - signaled worth: (occasion.signaledValue)")
}
buffer.addCompletedHandler { buffer in
    NSLog("Buffer accomplished - signaled worth: (occasion.signaledValue)")
}

buffer.commit()
buffer.waitUntilCompleted()

Output:

2022-01-09 23:46:08.774 Sync[76882:3531755] Steel GPU Body Seize Enabled
2022-01-09 23:46:08.805 Sync[76882:3531755] Begin - signaled worth: 0
2022-01-09 23:46:08.808 Sync[76882:3531764] Occasion notification - signaled worth: 1, buffer standing: 2 (Commited)
2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer scheduled - signaled worth: 2
2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer accomplished - signaled worth: 2

As you possibly can see eventListener logs buffer standing as .commited.
What’s the matter right here? Am I lacking one thing?

System: macOS 12.0.1, Apple M1 Professional, Xcode 13.2.1

[ad_2]

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments