【问题标题】:How to use CIContext drawImage:inRect:fromRect: with a CADisplayLink如何使用 CIContext drawImage:inRect:fromRect: 与 CADisplayLink
【发布时间】:2013-07-27 18:12:27
【问题描述】:

From the docs on CIContext drawImage:inRect:fromRect::

.. 在 iOS 6 上,此方法是异步的..

因此,如果我在 CADisplayLink 中使用它会遇到问题,因为它会继续以 60fps 的速度触发异步绘图,而实际绘图可能无法跟上。

- (void) displayLinkDidFire:(CADisplayLink *)displatLink;
{
    CFTimeInterval duration = [displatLink duration];
    CGFloat fps = round (1.0 / duration);
    NSLog(@"%f fps", fps); // Always logs 60 fps since drawImage is async

    // This method is fast since a CIImage is just a 'recipe' for an image
    CIImage * result = [Helper generateCIImage];

    // This drawing is unable to keep up with the calls to the displayLinkDidFire method
    [self.ciContext drawImage:result
                       inRect:self.destFrame
                     fromRect:self.targetFrame];
}

我该如何解决这个问题?


编辑 - 更多信息

我将 CoreImage 与 EAGLContext 一起使用(根据 WWDC 以获得更好的绘图性能)。

self.eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

self.ciContext = [CIContext
                  contextWithEAGLContext:self.eaglContext
                  options: @{kCIContextWorkingColorSpace:[NSNull null]} ];

GLKView *view = (GLKView *)self.view;
view.context = self.eaglContext;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

NSURL * testImageURL = [[NSBundle mainBundle] URLForResource:@"image" withExtension:@"jpg"];
NSAssert(nil != testImageURL, @"Image not found");

self.image = [CIImage imageWithContentsOfURL:testImageURL
                                     options:@{ kCIImageColorSpace:[NSNull null] }];

[EAGLContext setCurrentContext:self.eaglContext];

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkDidFire:)];

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

【问题讨论】:

  • 通常显示链接会做它需要做的事情,然后调用setNeedsDisplay 告诉视图刷新。这不会导致任何异步计时问题。
  • @Rob 我认为显示链接不会调用-setNeedsDisplay。它独立于标准的-drawRect: 视图更新周期工作。
  • @Rob - 感谢您的评论。我的设备上的可见 fps 约为 0.5,而 displayLink 以 60 fps 的速度发射,所以我认为异步是问题所在。你是说 drawImage 是异步的还是我应该使用 CADisplayLink 以外的东西来触发绘图无关紧要?
  • @Robert 您要么需要加快绘图速度,要么降低刷新率以适应绘图速度,要么需要跳帧。如果绘制图像需要 2 秒,那么 CADisplayLink 对您来说并没有多大用处。您不妨使用 while() 循环。根据您的更新,我建议您在开始渲染之前使用您的图像数据加载适当的 OpenGL 纹理。从文件加载到内存,然后复制到帧缓冲区可能太慢了。
  • @BoredAstronaut 同意,它不会自动调用setNeedsDisplay,但是在制作自己的动画时,让CADisplayLink 处理程序调用setNeedsDisplay 是一种常见的技术。并且显示链接调用的频率会自动匹配动画的FPS。

标签: ios objective-c cocoa-touch core-image


【解决方案1】:

解决方案是使用“OpenGL ES 渲染循环”而不是尝试使用CADisplayLink 构建一个。幸运的是,这很容易,因为 GLKViewController 会自动执行此操作:

GLKViewController 类提供所有标准视图控制器功能,但另外实现了 OpenGL ES 渲染循环。

唯一的缺点是,这与您使用GLKViewController 密切相关,而不是仅仅将GLKView 添加到现有的 UIView。要解决这个问题,您需要弄清楚如何实现自己的 OpenGL ES 渲染循环。

// The GLKViewController automatically calls this method
- (void) updateScreen
{        
    CIImage * result = [Helper generateCoreImage];

    // Clears the screen to a grey color 
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    [self.ciContext drawImage:result
                       inRect:self.destFrame
                     fromRect:self.targetFrame];

    // `display` needs to be called here according to the docs.
    GLKView *view = (GLKView *)self.view;
    [view display];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多