如何使用CIContext drawImage:inRect:fromRect:with CADisplayLink

时间:2013-07-27 14:31:05

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

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];
}

如何解决此问题?


修改 - 更多信息

我正在使用带有EAGLContext的CoreImage(根据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);

1 个答案:

答案 0 :(得分:1)

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

  

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

唯一的缺点是,这强烈要求您使用GLKViewController,而不是仅仅向现有的UIView添加GLKView。要解决这个问题,您需要了解如何实现自己的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];
}