只要應用程序轉到後臺,它必須停止調用OpenGL函數。但不知何故,當用戶按下主頁按鈕時,所有阻止OpenGL失敗的努力都失敗了,我的應用程序經常(但並非總是)崩潰。如何在應用程序後臺中暫停併發OpenGL繪圖?
它崩潰,
異常類型:EXC_BAD_ACCESS代碼:KERN_INVALID_ADDRESS在爲0x1 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClient
我的理解是,如果你的應用程序之後,調用OpenGL函數是不是在前臺了應用程序將因爲GPU不適用於應用程序,因此崩潰。
與OpenGL的呈現視圖具有調度隊列
self.drawingQueue = dispatch_queue_create("openglRenderQueue", DISPATCH_QUEUE_SERIAL);
它具有與並行的UIScrollView來呈現。所以有一個GCD semaphore讓隊列等待UIScrollView。
self.renderSemaphore = dispatch_semaphore_create(1);
我創建了一個CADisplayLink更新runloop:
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(update)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
self.displayLink = displayLink;
更新方法執行繪圖計算異步串行渲染隊列,並使用旗語等待UIScrollView的。它最終在主線程上提交同步。
- (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);
});
}
更新方法檢查主線程是否可以呈現。檢查看起來是這樣的:
- (BOOL)canRender {
UIApplicationState appState = [[UIApplication sharedApplication] applicationState];
return (appState != UIApplicationStateBackground && appState != UIApplicationStateInactive);
}
我最懷疑的一件事是停止隊列的併發問題。因爲即使在停止顯示鏈接之後,該塊也是異步觸發。
所以我覺得現在缺少的是,我還必須檢查-canRender之前我所說的任何OpenGL的功能在這個異步塊:
__block BOOL canRender = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
canRender = [self canRender];
});
if (!canRender) {
return;
}
OK,但現在我想象使這個檢查在渲染運行開始循環。 -canRender
說是的。然後我打電話給[sprite drawState:state];
。這個方法調用了很多gl函數。我認爲這是根本問題。因爲即使我的異步程序塊在主線程中檢查應用程序是否仍在前臺,當我繼續異步執行復雜繪圖時,3納秒以後,應用程序可能處於後臺狀態,並且出現了CRASH。
因此,即使我在每個單獨的gl函數調用之前在主線程上檢查了canRender,它可能是一個分裂納秒後的應用程序在後臺並崩潰。
有沒有辦法從內部關閉OpenGL,所以它忽略了對其功能的調用。我聽說過一種整理方法。我將不得不關閉它。但是如何?