Brad Larson delivered a solution for the CADisplayLink
freeze issue when scroll views are scrolling.
My OpenGL ES draw method is called by a CADisplayLink
, and I tried Brad's technique but can't make it work. The core problem is that my OpenGL ES view is hosted by a UIScrollView
, and when the UIScrollView
scrolls, the CADisplayLink
stops firing.
The technique Brad described is supposed to let the CADisplayLink
continue to fire even during scrolling (by adding it to NSRunLoopCommonModes
instead of the default runloop mode), and using a fancy semaphore trick the rendering callback is supposed to ensure that it doesn't render when UIKit is too occupied.
The problem is though that the semaphore trick prevents the rendering callback from drawing, no matter what.
First, I create the serial GCD queue and semaphore in the initWithFrame
method of my OpenGL ES view like this (on the main thread):
frameRenderingQueue = dispatch_queue_create("com.mycompany.crw", DISPATCH_QUEUE_SERIAL);
frameRenderingSemaphore = dispatch_semaphore_create(1);
The display link is created and added to NSRunLoopCommonModes
:
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(renderFrame)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
The render callback performs Brad's technique:
- (void)renderFrame {
if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0) {
NSLog(@"return"); // Gets called ALWAYS!
return;
}
dispatch_async(drawingQueue, ^{
@autoreleasepool {
// OpenGL ES drawing code
dispatch_semaphore_signal(frameRenderingSemaphore);
}
});
}
The dispatch_semaphore_wait
function always returns YES
and thus the render callback never renders. Even when I'm not scrolling.
I suppose that I missed something important here. Can someone point it out?
Edit: It seems to work only when I call dispatch_sync
instead of dispatch_async
, but according to Brad dispatch_async
would give better performance here.