OpenGL draws the black screen after returning from another display

advertisements

I am struggling whole day to find the answer to this.

Problem:

I have OpenGL view, i create it in IB, initialize all buffers and set its rendering loop in displayLink. It works great, everything is okay. But then i try creating another controller with this openGL view in root controller and present it using:

[self presentModalViewController:newPage animated:YES];

It shows up nicely, just like i wanted. It also works great with no problems found. It is also initiated from IB. But as soon as i use

[self dismissModalViewControllerAnimated:YES];

the animation does happen, the view does go down, but as it goes down it leaves "trash" behind it (parts of view in black background) and the previous openGL view stays black. I tried deleting and recreating displayLink but with no luck. I tried destroying/creating framebuffers again and i did manage to get it working once, but it took long time and since i am creating it from the view, i do not know if this is correct approach. Just to make it easier, here is some parts of my code:

- (BOOL)createFrameBuffer
{
    glGenFramebuffersOES(1, &viewFramebuffer);
    glGenRenderbuffersOES(1, &viewRenderbuffer);

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);

    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

    if (YES)
    {
        glGenRenderbuffersOES(1, &depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
    }

    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
    {
        NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }

    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);

    return YES;
    }

    }

    - (void)destroyFrameBuffer
    glDeleteFramebuffersOES(1, &viewFramebuffer);
    viewFramebuffer = 0;
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
    viewRenderbuffer = 0;

    if(depthRenderbuffer)
    {
        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
        depthRenderbuffer = 0;
    }

    - (void)layoutSubviews

    [EAGLContext setCurrentContext:context];

    [self draw:nil];

The internal init is my main init method.

 - (id)internalInit
{    

        CAEAGLLayer* eaglLayer = (CAEAGLLayer*) super.layer;
        eaglLayer.opaque = YES;

        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];

        if (!context || ![EAGLContext setCurrentContext:context]) {
            [self release];
            return nil;
        }

    [self createFrameBuffer];

    [self setupView:self];

        [self drawView: nil];

        CADisplayLink* displayLink;
        displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(draw:)];
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [displayLink setFrameInterval:1];

    return self;
}

The setupView: method basically creates viewport, sets frustum, all necessary variables and states. Nothing special.

Thanks in advance for all and any minute spent on this.


I had this same effect happen to me after some optimizations I had done proved to not work in every case, for me the problem present itself after dismissing the Game Center views, or after finishing playing a MPPlayer movie.

From apple's opengl template when you get a LayoutSubviews (which you will get after the top window disapears) you should destroy and recreate your frame buffers

- (void)layoutSubviews
{
    // The framebuffer will be re-created at the beginning of the next setFramebuffer method call.
    [self deleteFramebuffer];
}

After that the funcion [(EAGLView *)self.view setFramebuffer]; should be called to create the frame buffer again, the orginal template actually has this being called on every frame, but you only need to called it once after it's destroyed. (I put a var called first in there to do that)

I'll just put the routines here:

- (void)setFramebuffer
{
    if (context)
    {
        [EAGLContext setCurrentContext:context];

        if (!defaultFramebuffer)
            [self createFramebuffer];

        glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
        first = FALSE;

    }
}

- (void)createFramebuffer
{
if (context && !defaultFramebuffer)
{
    NSLog(@"Create Frame Buffer");

    [EAGLContext setCurrentContext:context];

    // Create default framebuffer object.
    glGenFramebuffersOES(1, &defaultFramebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);

    // Create color render buffer and allocate backing store.
    glGenRenderbuffersOES(1, &colorRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer *)self.layer];
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &framebufferWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &framebufferHeight);

    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

    // Need a depth buffer
    glGenRenderbuffersOES(1, &depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,  framebufferWidth, framebufferHeight);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
        NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER_OES));
}

}

So this setFramebuffer is called on the function called from displaylink. And I reset the var first to FALSE in my didfinish notifications from Game Center of MPPlayer.

If you can't find your problem try and debug what's being called at the EAGL object level, NSLog every function there and see if anything strange is going on with your buffers or bindings.