2013-10-06 4 views
6

アプリがバックグラウンドになるとすぐ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を内部からシャットダウンする方法はありますか。そのため、その関数への呼び出しは無視されます。仕上げ方法について聞いたことがあります。私はそれをシャットダウンする必要があります。しかしどうですか?

答えて

1

アプリケーションがバックグラウンドに入る前に、glFinish (...)と考えることができます。パイプラインのすべてのコマンドが終了するまでブロックされます。これには時間がかかりますが、潜在的に数msです​​。

同じトークンで、何らかの条件が満たされるまで(この場合、アプリケーションがバックグラウンドになくなるまで)、OpenGLでAPI呼び出しを無視するようにするのが最も簡単な方法です指定されたスレッドのアクティブコンテキストをNULLに設定します。これは、すべての呼び出しをノーオペレーションにするので、この状態でGL API呼び出しを行うとエラーは発生しません。アプリケーションがフォアグラウンドに戻ったときにアクティブなコンテキストを復元することができます。

問題の説明から、これらの両方の組み合わせが必要なように聞こえます。しかし、glFlush (...)で十分です。これは、OpenGLにバッファ内のすべてのコマンドをフラッシュするように指示します(基本的にキューに入れられていたものの実行を開始します)。 は、コマンドが戻る前に終了するのではなく、GLが何かを行う前に終了することを保証しません。

関連する問題