Non appena l'app passa allo sfondo, deve smettere di chiamare le funzioni OpenGL. Ma in qualche modo tutti gli sforzi per fermare OpenGL falliscono e la mia app spesso (ma non sempre) si blocca quando l'utente preme il pulsante home.Come interrompere il disegno OpenGL simultaneo durante lo sfondo dell'applicazione?
Si blocca con il tipo
eccezione: Codice EXC_BAD_ACCESS: KERN_INVALID_ADDRESS a 0x1 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClient
Per la mia comprensione se si chiama funzioni OpenGL dopo applicazione non è in primo piano più app arresto anomalo perché GPU non è disponibile per l'app.
La vista che rende con OpenGL ha una coda di invio
self.drawingQueue = dispatch_queue_create("openglRenderQueue", DISPATCH_QUEUE_SERIAL);
Deve rendering in parallelo con UIScrollView. Quindi esiste un GCD semaphore per consentire alla coda di attendere UIScrollView.
self.renderSemaphore = dispatch_semaphore_create(1);
Creo CADisplayLink aggiornare runloop:
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(update)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
self.displayLink = displayLink;
Il metodo di aggiornamento esegue calcoli disegno asincrona su seriale rendono coda e utilizza il semaforo aspettare UIScrollView. Alla fine esegue il commit della sincronizzazione sul thread principale.
- (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();
// Quickly grab the target game state for 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);
});
}
il metodo di aggiornamento di controllo dei thread principale se può rendere. Il controllo è simile al seguente:
- (BOOL)canRender {
UIApplicationState appState = [[UIApplication sharedApplication] applicationState];
return (appState != UIApplicationStateBackground && appState != UIApplicationStateInactive);
}
L'unica cosa che ho il sospetto che il più è un problema di concorrenza per fermare la coda. Poiché è asincrono, il blocco si attiva anche dopo aver interrotto il collegamento del display.
Quindi penso ciò che manca è che io devo anche controllare -canRender prima che chiami qualsiasi funzione OpenGL in questo blocco asincrona:
__block BOOL canRender = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
canRender = [self canRender];
});
if (!canRender) {
return;
}
OK ma ora immagino faccio questo controllo all'inizio del render corsa ciclo continuo. -canRender
dice SÌ. Quindi chiamo [sprite drawState:state];
. Questo metodo richiede molte funzioni gl. Penso che questo sia il problema alla radice. Perché anche se i miei blocchi asincroni controllano il thread principale se l'app è ancora in primo piano, quando continuo asincrono a fare il disegno complesso 3 nanosecondi più tardi l'app potrebbe trovarsi nello stato di background e nel CRASH.
Quindi, anche se controllo -canRender sul thread principale prima di ogni singola funzione gl chiamarlo potrebbe essere che un nanosecondo spaccatura tardi applicazione è in background e crash.
C'è un modo per arrestare OpenGL dall'interno, in modo che ignori le chiamate alle sue funzioni. Avevo sentito parlare di un metodo di finitura. Dovrei spegnerlo. Ma come?