Attempting to load / install a scene in the background thread results in the error "OpenGL error 0x0502 in - [CCSprite draw] 530"

I have a cocos2d v2.x application in which there is a scene in which there are a lot of sprites, nodes, configuration, data, etc. It loads quite expensive, so adding a scene to the director has a pause of 1/2 to 1 second, causing the current run animation to freeze until this scene is loaded. I have profiled the slowest methods and am trying to execute them asynchronously in the background thread and display a progress counter when it loads.

My implementation looks 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 does not work, as soon as the operation is called, it flies from EXC_BAD_ACCESS on line 523 CCTextureAtlas to

 glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])) ); 

and billions are displayed in the console log:

OpenGL Error 0x0502 in - [CCSprite draw] 530

what am I doing wrong?

UPDATE

I changed my code:

 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 he stopped the crash, and everything works, but 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 occur and how I can stop them?

EVEN OTHER UPDATE

It makes no sense ... obviously, these errors are due to adding sprites to CCSpriteBatchNode. If I put them on a regular CCNode, then everything will be fine. WHAT IS IT!!!!?!?!?!

AND ONE LAST FINAL UPDATE *

It seems that there are just a lot of stupid things that I just don't understand. I managed to remove these errors by 98%, but they still seem randomly too intermittent. I did a ton of debugger and trial and trial 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]; } 

Causes of random crashes - usually cocos removeFromParent tries to remove a square with an invalid index ... So, I tried to pause 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 from this OpenGL error 0x0502 in - [CCSprite draw] 530 in the log ......

So, I made some extreme protocols to try and find where these errors occur ...

 ... // 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 occur when coconuts wait for the fire of the planned selector ???? What the heck!? I can no longer tolerate this, and no one could help me, so the time has come for generosity.

+5
source share
2 answers

Here is how I do it:

Loadingscene

 -(void) onEnterTransitionDidFinish { [super onEnterTransitionDidFinish]; [NSThread detachNewThreadSelector:@selector(loadGameSceneInAnotherThread) toTarget:self withObject:nil]; } - (void) loadGameSceneInAnotherThread { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; CCGLView *view = (CCGLView*)[[CCDirector sharedDirector] view]; EAGLContext *auxGLcontext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]]; if( [EAGLContext setCurrentContext:auxGLcontext] ) { self.gameScene = [GameScene sceneWithLevelName:levelName]; self.gameLoadingDone = YES; glFlush(); [EAGLContext setCurrentContext:nil]; } [auxGLcontext release]; [autoreleasepool release]; } //this method ticks every 0.5sec -(void) checkIfGameSceneLoaded { if (self.gameLoadingDone) { [self unschedule:@selector(checkIfGameSceneLoaded)]; [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.75 scene:self.gameScene]]; } } 

However, I do not recommend loading the background for scenes .. because cocos2d is not intended for this ...

+5
source

Can you tell me why you are doing what you want? Difficult?

If I were you, I would do the following to load the asynchronous script.

  • Load the middle scene with a loading indicator or add it to the current one. + Create a new scene object.
  • Submitting asynchrounously expensive method for this new scene.
  • After that, replace the scene with CCDirector, send the operation synchronously

Use the GCD as it is now. You really don't want to paint your scene loading it, believe me.

+4
source

Source: https://habr.com/ru/post/1237733/


All Articles