I have a cocos2d v2.x app which has a scene that has a lot of sprites, nodes, configuration, data, etc... It is quite expensive to load, so much that when adding the scene to the director, there is a 1/2 to 1 second pause, causing the current running animations to freeze until this the scene is loaded. I profiled the slowest methods and am trying to execute them asynchronously in a background thread and display a progress spinner while it loads.
My implementation is something like this:
-(void)performAsyncLoad {
self.progressSpinner.visible = YES;
self.containerForLoadedStuff.visible = NO;
self.mainContext = [EAGLContext currentContext];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(loadDependencies)
object:nil];
[queue addOperation:operation];
}
-(void)loadDependencies {
@autoreleasepool {
glFlush();
EAGLSharegroup *shareGroup = [[(CCGLView*)[[CCDirector sharedDirector] view] context] sharegroup];
EAGLContext *context = [[EAGLContext alloc] initWithAPI:[[EAGLContext currentContext] API] sharegroup:shareGroup];
[EAGLContext setCurrentContext:context];
// ... expensive stuff here
// [self.containerForLoadedStuff addChild:sprites, etc...]
[self performSelectorOnMainThread:@selector(done) withObject:nil waitUntilDone:NO];
}
}
-(void)done {
glFlush();
[EAGLContext setCurrentContext:self.mainContext];
self.progressSpinner.visible = NO;
self.containerForLoadedStuff.visible = YES;
}
Unfortunately this is not working, once the operation is invoked, it crashes with EXC_BAD_ACCESS on line 523 of CCTextureAtlas on
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])) );
and the console log shows billions of:
OpenGL error 0x0502 in -[CCSprite draw] 530
what am I doing wrong?
UPDATE
I changed my code to do:
dispatch_queue_t queue = dispatch_queue_create("myqueue", NULL);
CCGLView *view = (CCGLView*)[[Director sharedDirector] view];
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]];
dispatch_async(queue, ^{
[EAGLContext setCurrentContext:context];
// expensive calls
glFlush();
[self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO];
[EAGLContext setCurrentContext:nil];
});
And it stopped the crashing, and everything works, however I still get a billion:
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
Any ideas why these errors are happening and how I can stop them?
YET ANOTHER UPDATE
This makes no sense... apparently these errors come from adding sprites to a CCSpriteBatchNode. If I put those on a regular CCNode then everything works fine. WHAT THE HELL!?!?!?!?!
AND ONE LAST FINAL UPDATE*
It appears that there is just a whole lot of nonsense that I just don't understand. I've managed to make these errors go away 98%, but they still seem to randomly happen extremely intermittently. I did a ton of debugger and trial & error testing, and found that this code:
-(void)loadDependencies {
dispatch_queue_t queue = dispatch_queue_create("myqueue", NULL);
CCGLView *view = (CCGLView*)[[Director sharedDirector] view];
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]];
dispatch_async(queue, ^{
[EAGLContext setCurrentContext:context];
[self.myObject doExpensiveStuff];
glFlush();
[self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO];
[EAGLContext setCurrentContext:nil];
});
}
-(void)done {
[self.delegate completedAsyncStuff];
}
Caused random crashes-- usually cocos removeFromParent trying to remove a quad at an invalid index... So then I tried pausing the object before doing work on it..
//... background thread stuff:
[self.myObject pauseSchedulerAndActions];
[self.myObject doExpensiveStuff];
[self.myObject resumeSchedulerAndActions];
Then it no longer crashed, but put gazillions of those OpenGL error 0x0502 in -[CCSprite draw] 530 in the log......
So then I did some extreme logging to try to find where these errors were happening...
... // previous code above... etc
NSLog(@"gl flush...");
glFlush();
NSLog(@"after gl flush...");
[self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO];
[EAGLContext setCurrentContext:nil];
});
}
-(void)done {
NSLog(@"done scheduling notify delegate");
[self scheduleOnce:@selector(notifyDelegate) delay:1];
}
-(void)notifyDelegate {
NSLog(@"about to notify delegate");
[self.delegate completedAsyncStuff];
}
In my log I see:
gl flush
after gl flush
done scheduling notify delegate
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
OpenGL error 0x0502 in -[CCSprite draw] 530
about to notify delegate
So these errors happen when cocos is waiting to fire of a scheduled selector???? What the hell!? I can't stand this anymore, and no one has been able to help me, so it's time for a bounty.