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

.. On iOS 6, this method is asynchronous ..

So if I am using it in a CADisplayLink it runs into a problem since it will keep firing off asynchronous draws at 60fps while the actual drawing might not be able to keep up.

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

How do I get around this issue?


Edit - more info

I am using CoreImage with an EAGLContext (for better drawing performance according to WWDCs).

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);
有帮助吗?

解决方案

The solutuion was to use an "OpenGL ES rendering loop " instead of trying to build one with CADisplayLink. Luckily this was easy since a GLKViewController does this automtically:

The GLKViewController class provides all of the standard view controller functionality, but additionally implements an OpenGL ES rendering loop.

The only down side is that this strongly ties you to using a GLKViewController instead of a just adding a GLKView to an existing UIView. To get around this you need to work out how to implement your own OpenGL ES rendering loop.

// 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];
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top