Reputation: 418
Whenever I add the CAMetalLayer
to the NSView
, the [CAMetalLayer nextDrawable]
method will pass nil
after 3 successful id<CAMetalDrawable>
.
I tried two different ways to configure the setup. One, I used MTKView and used its CAMetalLayer
, it didn't work. Second, used NSView
and created new CAMetalLayer
. That didn't work also. I had weird issues.
I want to know anyone else is having this problem and if anyone know a solution to resolve this.
Additional notes:
I don't want to use MTKView draw system by overriding its methods (not yet). Also this is not a problem on iOS 8 and I didn't tried my code with the beta release of iOS 9 (not yet).
Update
I reroute my drawable calls to use the MTKViewDelegate
delegate. And from the drawInView
delegate method, I was able to retrieve consistent drawable frames. However, I still would like to use the nextDrawable
method directly from CAMetalLayer
. Hope this helps anyone else.
Upvotes: 3
Views: 2266
Reputation: 949
Use @autoreleasepool
for render in drawable.
https://forums.developer.apple.com/thread/15102
Upvotes: 0
Reputation: 418
I forgot to come back to this.
This was fixed
with OSX Beta 4
. nextDrawable
method is working correctly and passing back usable CAMetalDrawable
objects. I guess I should've waited until the release version came out before posting this. I just wanted to let everyone else know about this problem back when the beta version was first released.
Upvotes: 0
Reputation: 3104
I had this same issue, and asked Metal devs at WWDC 15.
How MTKView
works: MTKView
has limited number of drawables (probably 3), so when you are encoding frames there are few drawables you can draw to.
What you are doing: Your scene is probably quite simple, so you CPU can encode frames really fast. So it seems like, when CPU is 4 frames ahead of GPU, you ask for next drawable and since all (3) drawables are in use, it fails.
Solution: You need to use semapthore to wait for drawable when there is no free one.
Here's code to use:
let inflightSemaphore = dispatch_semaphore_create(3)
func drawInView(view: MTKView) {
// use semaphore to encode 3 frames ahead
dispatch_semaphore_wait(inflightSemaphore, DISPATCH_TIME_FOREVER)
self.update()
let commandBuffer = commandQueue.commandBuffer()
let renderEncoder = commandBuffer.renderCommandEncoderWithDescriptor(view.currentRenderPassDescriptor!)
renderEncoder.drawPrimitives()
// use completion handler to signal the semaphore when this frame is completed allowing the encoding of the next frame to proceed
commandBuffer.addCompletedHandler{ [weak self] commandBuffer in
if let strongSelf = self {
dispatch_semaphore_signal(strongSelf.inflightSemaphore)
}
return
}
commandBuffer.presentDrawable(view.currentDrawable!)
commandBuffer.commit()
}
This is not documented anywhere! The only written mention of that is in iOS project template (File -> New -> Project -> Game -> Pick Metal) in GameViewController
.
I already filled a radar on this (no response yet), and would appreciate if you do the same https://bugreport.apple.com
Also you may find useful my github repo https://github.com/haawa799/RamOnMetal
Upvotes: 4