为什么即使我不滚动,dispatch_semaphore_wait()也会一直返回YES?

时间:2012-09-27 18:09:51

标签: opengl-es uikit grand-central-dispatch cadisplaylink

当滚动视图滚动时,Brad Larson为CADisplayLink冻结问题提供了solution

我的OpenGL ES绘制方法由CADisplayLink调用,我尝试了Brad的技术但无法使其工作。核心问题是我的OpenGL ES视图由UIScrollView托管,当U IScrollView滚动时,CADisplayLink停止发射。

Brad描述的技术应该让CADisplayLink在滚动期间继续激活(通过将其添加到NSRunLoopCommonModes而不是默认的runloop模式),并使用花哨的信号量欺骗渲染回调应该确保当UIKit太占用时它不会呈现。

问题是,无论如何,信号量技巧都会阻止渲染回调。

首先,我在我的OpenGL ES视图的initWithFrame方法中创建串行GCD队列和信号量(在主线程上):

frameRenderingQueue = dispatch_queue_create("com.mycompany.crw", DISPATCH_QUEUE_SERIAL);
frameRenderingSemaphore = dispatch_semaphore_create(1);

创建显示链接并将其添加到NSRunLoopCommonModes

CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(renderFrame)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

渲染回调执行Brad的技术:

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

dispatch_semaphore_wait函数始终返回YES,因此渲染回调永远不会呈现。即使我不滚动。

我想我错过了一些重要的事情。有人能说出来吗?

修改:它似乎仅在我拨打dispatch_sync而不是dispatch_async时才有效,但根据布拉德dispatch_async会在此处提供更好的效果。

1 个答案:

答案 0 :(得分:0)

我必须将代码的结构更改为:

- (void)renderFrame {
    dispatch_async(drawingQueue, ^{
        if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0) {
            return;
        }

        @autoreleasepool {
            // Drawing code...
        }

        dispatch_semaphore_signal(frameRenderingSemaphore);
    });
}

我以这种方式重组后,dispatch_semaphore_wait调用一直停止返回YES。我不确定这是否实际上只是禁用了Brad的信号量等待技巧。但它确实有效。