2013-10-06 5 views
6

앱이 백그라운드로 이동하자마자 OpenGL 기능 호출을 중단해야합니다. 하지만 어떻게 든 사용자가 홈 버튼을 누르면 OpenGL을 중지하려는 모든 노력이 실패하고 종종 내 앱이 중단됩니다 (하지만 항상 그런 것은 아닙니다).애플 backgrounding하는 동안 동시 OpenGL 그리기를 중단하는 방법?

예외 유형과 충돌 : EXC_BAD_ACCESS 코드 : KERN_INVALID_ADDRESS를 0x1로 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClient

에서 나의 이해하는 앱 후에는 OpenGL 함수를 호출하면됩니다하지 전경에 더 이상 응용 프로그램 것 GPU를 앱에서 사용할 수 없기 때문에 충돌이 발생합니다. OpenGL은로 렌더링

보기는 발송 대기열 그것은있는 UIScrollView와 병렬 렌더링하는

self.drawingQueue = dispatch_queue_create("openglRenderQueue", DISPATCH_QUEUE_SERIAL); 

있다. 따라서 GCD semaphore을 사용하면 큐에서 UIScrollView를 기다릴 수 있습니다. 큐를 렌더링하고있는 UIScrollView 기다릴 세마포어를 사용하여 일련의

CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(update)]; 
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 
self.displayLink = displayLink; 

Update 메소드 드로잉 수행 계산 비동기 :

self.renderSemaphore = dispatch_semaphore_create(1); 

난 runloop를 업데이트하는 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); 
} 

내가 가장 의심 한 것은 큐를 중단하는 동시성 문제입니다. 비동기이기 때문에 표시 링크를 중지 한 후에도 블록이 실행됩니다. 지금

__block BOOL canRender = YES; 
dispatch_sync(dispatch_get_main_queue(), ^{ 
    canRender = [self canRender]; 
}); 
if (!canRender) { 
    return; 
} 
OK

하지만 실행 렌더링의 시작 부분에이 검사를 할 상상 :

그래서 내가 뭘없는 것은 내가이 비동기 블록에서 OpenGL을 함수를 호출하기 전에 나는 또한 -canRender 확인해야한다는 생각 고리. -canRender에 YES라고 표시되어 있습니다. 그런 다음 [sprite drawState:state];으로 전화합니다. 이 메서드는 많은 gl 함수를 호출합니다. 나는 이것이 근본적인 문제라고 생각한다. 응용 프로그램이 여전히 포 그라운드에있는 경우 내 비동기 블록이 주 스레드에서 검사하더라도 3 초 후에 복잡한 그림을 그리기 위해 비동기를 계속하면 응용 프로그램이 백그라운드 상태 및 CRASH 상태가 될 수 있습니다.

그래서 모든 단일 gl 함수 호출 전에 주 스레드에서 -canRender를 실행해도 나중에 분할 된 나노초가 백그라운드에 있고 충돌 할 수 있습니다.

OpenGL을 내부에서 종료하여 해당 기능 호출을 무시하는 방법이 있습니까? 나는 마무리 방법에 대해 들었다. 나는 그것을 폐쇄해야 할 것이다. 그러나 어떻게?

답변

1

응용 프로그램이 백그라운드로 들어가기 전에 glFinish (...)을 고려할 수 있습니다. 파이프 라인의 모든 명령이 완료 될 때까지 차단됩니다. 잠재적으로 몇 ms가 걸릴 수 있습니다.

동일한 토큰을 사용하면 일부 조건이 충족 될 때까지 OpenGL에서 API 호출을 무시하도록하고 싶다면 (이 경우 애플리케이션이 더 이상 백그라운드에 없을 때까지) 가장 쉬운 방법은 다음과 같습니다. 주어진 스레드에 대한 활성 컨텍스트를 NULL로 설정하십시오. 이렇게하면 각 호출마다 아무런 조작도하지 않게되므로이 상태에서 GL API 호출을 할 때 오류가 생성되지 않습니다. 응용 프로그램을 포 그라운드로 되돌릴 때 활성 컨텍스트를 복원 할 수 있습니다.

문제 설명을 통해이 두 가지를 조합해야 할 수도 있습니다. 그러나 glFlush (...)이면 충분합니다. 버퍼에있는 모든 명령을 플러시하도록 OpenGL에 지시합니다 (기본적으로 대기중인 모든 것을 실행하기 시작합니다). 이 리턴되기 전에 끝내기 명령을 기다리지는 않지만 GL이 다른 작업을 수행하기 전에 끝내도록 보장하지 않습니다.