ios - How to halt concurrent OpenGL drawing during app backgrounding? -
as app goes background must stop calling opengl functions. somehow efforts stop opengl fail , app (but not always) crashes when user presses home button.
it crashes
exception type: exc_bad_access code: kern_invalid_address @ 0x1 libgpusupportmercury.dylib gpus_returnnotpermittedkillclient
to understanding if call opengl functions after app not in foreground anymore app crash because gpu not available app.
the view renders opengl has dispatch queue
self.drawingqueue = dispatch_queue_create("openglrenderqueue", dispatch_queue_serial);
it has render in parallel uiscrollview. there gcd semaphore let queue wait uiscrollview.
self.rendersemaphore = dispatch_semaphore_create(1);
i create cadisplaylink update runloop:
cadisplaylink *dl = [[uiscreen mainscreen] displaylinkwithtarget:self selector:@selector(update)]; [dl addtorunloop:[nsrunloop currentrunloop] formode:nsrunloopcommonmodes]; self.displaylink = displaylink;
the update method performs drawing calculations async on serial render queue , uses semaphore wait uiscrollview. commits sync on main thread.
- (void)update { dispatch_async(drawingqueue, ^{ if (dispatch_semaphore_wait(rendersemaphore, dispatch_time_now) != 0) { return; } @autoreleasepool { [eaglcontext setcurrentcontext:context]; glbindframebufferoes(gl_framebuffer_oes, framebuffer); glviewport(0, 0, width, height); glmatrixmode(gl_modelview); glclear(gl_color_buffer_bit); glloadidentity(); // grab target game state rendering gamestate state = targetstate; [sprite drawstate:state]; dispatch_sync(dispatch_get_main_queue(), ^{ if ([self canrender]) { bool isanimating = [self isanimating]; if (isanimating && displaylink) { [eaglcontext setcurrentcontext:context]; glbindrenderbufferoes(gl_renderbuffer_oes, renderbuffer); if (displaylink != nil) { [context presentrenderbuffer:gl_renderbuffer_oes]; } } } }); } dispatch_semaphore_signal(rendersemaphore); }); }
the update method checks on main thread if can render. check looks this:
- (bool)canrender { uiapplicationstate appstate = [[uiapplication sharedapplication] applicationstate]; return (appstate != uiapplicationstatebackground && appstate != uiapplicationstateinactive); }
the 1 thing suspect concurrency problem halt queue. because async block fires after stopped display link.
so think missing must check -canrender before call opengl function in async block:
__block bool canrender = yes; dispatch_sync(dispatch_get_main_queue(), ^{ canrender = [self canrender]; }); if (!canrender) { return; }
ok imagine make check @ beginning of render run loop. -canrender
says yes. call [sprite drawstate:state];
. method calls lot of gl functions. think root problem. because if async blocks checks on main thread if app still in foreground, when continue async complex drawing 3 nanoseconds later app in background state , crash.
so if check -canrender on main thread before every single gl function call split nanosecond later app in background , crash.
is there way shut down opengl inside out ignores calls functions. had heard finishing method. have shut down. how?
you consider glfinish (...)
before allowing application go background. block until every command in pipeline finishes. take while though, potentially several ms.
by same token, if want make opengl ignore api calls until condition met (in case, until application no longer in background) easiest way set active context given thread null. make each , every call no-op, so no error generated when make gl api call in state. can restore active context when application brought foreground.
from problem description, sounds may need combination of both of these things. however, glflush (...)
may sufficient - tell opengl flush of commands in buffer (basically start executing being queued up). not wait commands finish before returning, guarantees finish before gl else.
Comments
Post a Comment