Reputation: 38213
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);
Upvotes: 2
Views: 4335
Reputation: 38213
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];
}
Upvotes: 1