尝试在后台线程中加载/设置场景会导致" OpenGL错误0x0502 - [CCSprite draw] 530"

时间:2015-12-09 09:09:46

标签: opengl-es cocos2d-iphone

我有一个cocos2d v2.x应用程序,它有一个场景,有很多精灵,节点,配置,数据等......加载非常昂贵,以至于在将场景添加到导演时,暂停1/2到1秒,导致当前运行的动画冻结,直到加载场景。我描述了最慢的方法,并尝试在后台线程中异步执行它们,并在加载时显示进度微调器。

我的实现是这样的:

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

不幸的是,这不起作用,一旦调用该操作,它就会在CCTextureAtlas的第523行与EXC_BAD_ACCESS崩溃

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

,控制台日志显示数十亿:

  

OpenGL错误0x0502 in - [CCSprite draw] 530

我做错了什么?

更新

我改变了我的代码:

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

它停止了崩溃,所有都可以,但是我仍然有十亿:

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

为什么会发生这些错误以及如何阻止它们?

再次更新

这没有任何意义......显然这些错误来自于向CCSpriteBatchNode添加精灵。如果我将它们放在常规CCNode上,那么一切正常。什么地狱!?!?!?!?!

以及最后一次最终更新*

似乎有很多废话,我只是不明白。我设法使这些错误消失了98%,但它们似乎仍然间歇性地随机发生。我做了大量的调试和试用&错误测试,发现这段代码:

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

导致随机崩溃 - 通常是cocos removeFromParent尝试删除无效索引处的四元组...所以我尝试暂停该对象然后再对其进行处理..

//... background thread stuff:
[self.myObject pauseSchedulerAndActions];
[self.myObject doExpensiveStuff];
[self.myObject resumeSchedulerAndActions];

然后它不再崩溃,但在日志中放入了那些OpenGL错误0x0502 - [CCSprite draw] 530 ......

然后我做了一些极端的日志记录,试图找出这些错误发生的地方......

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

在我的日志中,我看到:

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

因此,当cocos等待计划选择器的激活时会发生这些错误????我勒个去!?我不能忍受这个了,没有人能够帮助我,所以现在是获得赏金的时候了。

1 个答案:

答案 0 :(得分:4)

你能告诉我为什么你做你想做的事情很难吗?

如果我是你,我会做以下事情,加载场景异步。

  1. 使用加载指示符加载中间场景,或将其添加到当前场景。 +创建一个新的场景对象。
  2. 为新场景发送 asynchrounously 昂贵的方法。
  3. 完成后,用CCDirector替换场景,同步发送操作
  4. 立即使用GCD。相信我,你真的不想在装载时画出你的场景。