アプリがバックグラウンドになるとすぐOpenGL関数の呼び出しを停止する必要があります。しかし、どうにかして、OpenGLを止めるためのすべての努力が失敗し、ユーザのホームボタンを押したときに私のアプリが頻繁に(常にそうとは限りません)クラッシュする。アプリケーションのバックグランド中に同時にOpenGL描画を停止する方法はありますか?
それは
例外タイプでクラッシュ:アプリがフォアグラウンドではないの後にアプリもうOpenGLの関数を呼び出す場合は意志私の理解には0x1 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClient
でKERN_INVALID_ADDRESS:EXC_BAD_ACCESSコードアプリケーションでGPUを使用できないためクラッシュする
のOpenGLでレンダリングビューは、それはUIScrollViewのと並行してレンダリングする必要のあるディスパッチキュー
self.drawingQueue = dispatch_queue_create("openglRenderQueue", DISPATCH_QUEUE_SERIAL);
を持っています。そのため、キューにUIScrollViewが待機するようにするには、GCD semaphoreがあります。キューをレンダリングし、UIScrollViewのを待つためにセマフォを使用してシリアルに
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(update)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
self.displayLink = displayLink;
更新方法は、描画を行う計算非同期:
self.renderSemaphore = dispatch_semaphore_create(1);
私は実行ループを更新するCADisplayLinkを作成します。最終的にメインスレッドで同期をコミットします。
- (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);
}
私が一番疑う点は、キューを停止するための並行性の問題です。非同期であるため、ブロックは表示リンクを停止した後でも起動します。
だから私は何不足していることは、私は、この非同期ブロック内の任意のOpenGLの関数を呼び出す前に、私も-canRenderチェックしなければならないということだと思う:
__block BOOL canRender = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
canRender = [self canRender];
});
if (!canRender) {
return;
}
OKを今私は、レンダリングの実行の開始時には、このチェックを行う想像ループ。 -canRender
と答えてください。その後私は[sprite drawState:state];
と呼ぶ。このメソッドは多くのgl関数を呼び出します。私はこれが根本的な問題だと思う。私の非同期ブロックは、アプリケーションがフォアグラウンドにまだ残っているかどうかをチェックしても、3ナノ秒後に複雑な描画を行うために非同期を続けると、アプリケーションはバックグラウンド状態とクラッシュ状態になる可能性があります。
したがって、毎回のgl関数呼び出しの前にメインスレッドの-canRenderをチェックしても、後で分割されたナノ秒後のアプリケーションがバックグラウンドでクラッシュする可能性があります。
OpenGLを内部からシャットダウンする方法はありますか。そのため、その関数への呼び出しは無視されます。仕上げ方法について聞いたことがあります。私はそれをシャットダウンする必要があります。しかしどうですか?