1

Brad Larson为滚动视图滚动时的冻结问题提供了解决方案。CADisplayLink

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

Brad 描述的技术应该让CADisplayLink即使在滚动期间也能继续触发(通过将其添加到NSRunLoopCommonModes而不是默认的 runloop 模式),并且使用花哨的信号量技巧渲染回调应该确保它在 UIKit 时不会渲染太占了。

问题在于信号量技巧无论如何都会阻止渲染回调绘制。

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

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会在这里提供更好的性能。

4

1 回答 1

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 的信号量等待技巧。但它有效。

于 2012-09-27T18:43:15.743 回答