CADisplayLink OpenGL渲染会破坏UIScrollView行为

Ada*_*dam 24 iphone opengl-es

SO上有一些类似的问题(最后的链接),但是没有一个能让我解决我的问题,所以这里有:

我正在使用OpenGL渲染来制作图像平铺和缓存库以供在游戏项目中使用,我想劫持UIScrollView的物理特性以允许用户在图像周围导航(因为它有很好的反弹行为,可能是好好利用它).所以我有一个UIScrollView,我用它来获取纹理的渲染视图,但是有一个问题 - 在滚动视图上移动会阻止CADisplayLink触发,直到用户完成滚动(这看起来很糟糕).一个临时修复是使用NSRunLoopCommonModes而不是默认的运行模式,但不幸的是,这打破了我正在测试的某些手机上的滚动视图行为的某些方面(3GS和模拟器似乎工作正常,而iPhone4和3G没有"T).

有谁知道如何解决CADisplayLink和UIScrollView之间的这种冲突,或者知道如何修复在其他运行模式下工作的UIScrollView?提前致谢 :)

承诺链接到类似的问题: UIScrollView损坏并停止使用OpenGL渲染滚动(相关的CADisplayLink,NSRunLoop)

在iPhone上拖动UIScrollView时,OpenGL ES视图中的动画会冻结

Bra*_*son 43

由CADisplayLink触发的主线程的缓慢更新可能会破坏UIScrollView的滚动行为.在使用NSRunLoopCommonModesCADisplayLink 时,您的OpenGL ES渲染可能需要足够长的时间才能使每个帧都丢失UIScrollView 的时间.

解决此问题的一种方法是使用Grand Central Dispatch串行队列在后台线程上执行OpenGL ES呈现操作.我在最近的Molecules更新中做到了这一点(源代码可以在该链接中找到),在使用NSRunLoopCommonModes我的CADisplayLink 进行测试时,我看不到屏幕上的表视图的本机滚动行为的任何中断与渲染同时进行.

为此,您可以创建GCD串行调度队列,并将其用于特定OpenGL ES上下文的所有渲染更新,以避免两个操作同时写入上下文.然后,在您的CADisplayLink回调中,您可以使用如下代码:

if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
{
    return;
}

dispatch_async(openGLESContextQueue, ^{

    [EAGLContext setCurrentContext:context];

    // Render here

    dispatch_semaphore_signal(frameRenderingSemaphore);
});
Run Code Online (Sandbox Code Playgroud)

其中frameRenderingSemaphore较早创建如下:

frameRenderingSemaphore = dispatch_semaphore_create(1);
Run Code Online (Sandbox Code Playgroud)

如果一个不在执行的中间,此代码将仅向队列添加新的帧渲染操作.这样,CADisplayLink可以连续触发,但如果帧需要超过1/60秒处理,它将不会使挂起的渲染操作重载队列.

再次,我在我的iPad上尝试了这一点,发现表视图的滚动动作没有中断,只是因为OpenGL ES渲染消耗了GPU周期而略微减速.

  • @ranReloaded - 通过在非主线程上进行渲染,您可以看到一些不错的性能改进,因为并行化GPU和CPU绑定处理(在GPU仍在最后一组上工作时从CPU上传数据,等等.).这对多核系统特别有帮助,我已经看到渲染性能的提升高达40%,仅仅是渲染帧渲染.即使在单核机器上,我也看到了10-20%的改进. (3认同)