Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random crash on iPhone OpenGL app when navigating

I'm working on a iPhone application which is hybrid OpenGL ES and regular iPhone UI. This means there is an EAGLView greeting the user, then some regular UIViews that gets pushed over it (there is a UINavigationController as root controller).

I've got a random (but very frequent) crash when navigating back from a subview. Here is a (...censored...) stack trace, from a Release build, but it crashes just the same in Debug.

#0  0x006863d0 in GetFBOBuffers ()
#1  0x00660120 in TerminateScene ()
#2  0x00660314 in FlushScene ()
#3  0x00660cd4 in FlushHW ()
#4  0x0066a6a0 in GLESPresentView ()
#5  0x323533a4 in -[EAGLContext presentRenderbuffer:] ()
#6  0x000026c0 in -[EAGLView presentFramebuffer] (self=0x11ce60, _cmd=<value temporarily unavailable, due to optimizations>) at (...)/Classes/EAGLView.m:157
#7  0x00004fdc in -[(...)ViewController drawFrame] (self=<value temporarily unavailable, due to optimizations>, _cmd=<value temporarily unavailable, due to optimizations>) at (...)    ViewController.m:380
#8  0x336ebd9a in __NSFireTimer ()
#9  0x323f54c2 in CFRunLoopRunSpecific ()
#10 0x323f4c1e in CFRunLoopRunInMode ()
#11 0x335051c8 in GSEventRunModal ()
#12 0x324a6c30 in -[UIApplication _run] ()
#13 0x324a5230 in UIApplicationMain ()
#14 0x0000214c in main (argc=1, argv=0x2ffff568) at (...)/main.m:14

Here is a list of things I know:

  • My app doesn't get a memory warning.
  • My app has no identified leak under Instruments.
  • No crash on Simulator, but sometimes a very noticeable lag.
  • There is a significant amount of released data in Instruments/OpenGL/ResourceBytes just before the crash.
  • I'm using both VBOs and vertex/texcoord/normals arrays.

So I know it must be some kind of data that gets released or destroyed, but I don't know how to find which. Any tips and tricks would be appreciated ;-)

UPDATE:

After setting some breakpoints, moving along the stack, poking at various variables, I've found the reason for the crash, but not yet the source.

In EAGLView, in the method presentFramebuffer where and when the crash occurs, the colorRenderBuffer ivar is 0 if I can believe gdb, even though trying to breakpoint when it's 0 doesn't seem to work.

It seems the deleteFrameBuffer call from layoutSubviews isn't matched by a createFramebuffer.

UPDATE 2:

Lots of breakpoints later... I've found a wrong situation: [EAGLView layoutSubviews] gets called in the middle of a drawFrame ! So the buffers get deleted while in use... BAM!

Now how do I fix that?

like image 523
jv42 Avatar asked Nov 04 '10 15:11

jv42


3 Answers

I haven't found a 'proper' fix yet, but I've added a workaround.

In presentFramebuffer, I set a boolean around the rendering :

if (context)
{
    isRendering_PATCH_VARIABLE = YES;

    [EAGLContext setCurrentContext:context];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

    success = [context presentRenderbuffer:GL_RENDERBUFFER_OES];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);

    isRendering_PATCH_VARIABLE = NO;
}

and in deleteFramebuffer, I check this boolean:

if (isRendering_PATCH_VARIABLE)
{
    NSLog(@"GOTCHA - CRASH AVOIDED");   
}

if (context && !isRendering_PATCH_VARIABLE)
{
    // ...
}

It doesn't seem to have side-effects (like broken display, etc), so I'll leave it like that for the moment.

like image 57
jv42 Avatar answered Oct 20 '22 08:10

jv42


Here's wild guess based on something I did recently.

What I did was break up the loading stage. I wanted to show a progress bar as I loaded up a number of resources - it's a slow process so I wanted to provide some user feedback.

My first step was similar to the OpenGL ES example provided with Xcode in that I called an init on an ES?Renderer. But after that I stalled the process so I could load other resources.

To cut a long story short, because of my re-arrangement of code the [EAGLView layoutSubviews] was never called after my initialisation. I didn't get a crash, but nothing much happened after this point.

What I had to do was that after I finished initialising OpenGL's context and loading all my data, I had to manually call the [EAGLView layoutSubviews]. This seemed to fix things for me.

Maybe you need to try something similar. After you initialise your OpenGL context and data, call the [EAGLView layoutSubviews] before you get into your drawing routines. Maybe this will stop this call again reappearing in your rendering step and crashing.

like image 35
No one in particular Avatar answered Oct 20 '22 07:10

No one in particular


A stab in the dark: Your device gets low on memory, the application receives a memory warning and the controller responsible for the GL view releases the view, which is something you did not count with? Does the problem go away when you suppress the default didReceiveMemoryWarning?

- (void) didReceiveMemoryWarning { /* nothing we can do, sorry */ }

…or maybe you are calling OpenGL from another thread that does not have the context?

like image 45
zoul Avatar answered Oct 20 '22 09:10

zoul