Android가 일시 중지 될 때 OpenGL 컨텍스트를 잃는 해결 방법?


40

안드로이드 문서는 말합니다 :

EGL 렌더링 컨텍스트가 유실되는 상황이 있습니다. 일반적으로 장치가 절전 모드로 전환 된 후 깨어날 때 발생합니다. EGL 컨텍스트가 유실되면 해당 컨텍스트와 연관된 모든 OpenGL 자원 (예 : 텍스처)이 자동으로 삭제됩니다. 렌더링을 올바르게 유지하려면 렌더러가 여전히 필요한 손실 된 리소스를 다시 만들어야합니다. onSurfaceCreated (GL10, EGLConfig) 메소드는이를 수행하기에 편리한 위치입니다.

그러나 OpenGL 컨텍스트에서 모든 텍스처를 다시로드해야하는 것은 고통스럽고 일시 중지 후 앱을 다시 시작할 때 사용자에게 게임 경험을 손상시킵니다. 나는 "앵그리 버드"가 어떻게 든 이것을 피한다는 것을 알고 있습니다. 나는 그것을 달성하는 방법에 대한 제안을 찾고 있습니까?

Android NDK r5 (CrystaX 버전)로 작업하고 있습니다. 문제에 대한 해킹 을 발견 했지만 전체 사용자 정의 SDK 버전을 작성하지 않으려 고합니다.


수면 및 깨우기는 장치를 참조하므로 사용자가 게임을 일시 중지하거나 프로세스를 전환하는 동안 EGL 컨텍스트가 느슨해집니다.
Ali1S232

답변:


22

Replica Island에는 이 문제를 해결하고 이전 Android 버전에서 작동 하는 수정 된 버전 의 GLSurfaceView가 있습니다. 에 따르면 크리스 Pruett는 :

기본적으로 원래의 GLSurfaceView를 해킹하여 매우 구체적인 문제를 해결했습니다. 모든 OpenGL 상태를 버리지 않고 앱 내에서 다른 활동으로 이동하고 싶었습니다. 주요 변경 사항은 EGLSurface를 EGLContext에서 분리하고 전자를 onPause ()에서 버리는 것이었지만 컨텍스트가 명시 적으로 손실 될 때까지 후자를 보존하는 것이 었습니다. GLSurfaceView (기본적으로 작성하지 않은)의 기본 구현은 활동이 일시 중지 될 때 모든 GL 상태를 버리고 다시 시작할 때 onSurfaceCreated ()를 호출합니다. 즉, 게임에서 대화 상자가 나타나면 모든 텍스처를 다시로드해야했기 때문에 대화 상자를 닫으면 지연이 발생했습니다.

기본 GLSurfaceView를 사용해야합니다. 내 기능과 동일한 기능이 있어야하는 경우 내 기능을 볼 수 있습니다. 그러나 내가 한 일을하면 일부 핸드셋에서 모든 종류의 끔찍한 드라이버 버그가 노출되고 (파일 끝 부분의 긴 주석 참조) 기본 버그를 사용하면 모든 혼란을 피할 수 있습니다.

편집 : 방금 비슷한 해킹에 대한 링크를 게시했습니다. 허니컴 이전에 내장 솔루션이 없다고 생각합니다. Replica Island는 많은 장치에서 작동하는 인기있는 게임이므로 Chris의 구현 및 의견이 도움이 될 수 있습니다.


1
이를 피하기 위해 다양한 접근 방식을 시도한 후 가장 좋은 해결책은 컨텍스트를 다시 작성하기 위해 앱을 코딩하는 것입니다. 이것은 매우 낭비적인 접근법이지만 좋은 해결책이없는 것처럼 보이지 않습니다. code.google.com/p/android/issues/detail?id=12774
Nick Gotch

9

Chris Pruett (Replica Island, Wind-Up Knight 등)가 1 ~ 2 년 동안 나에게 전달한 다른 답변을 추가하고 싶습니다. setPreserveEglContextOnPause (true)가 4.3에서 작동하지 않는 것이므로 2013 년에 특히 유용합니다. (나는 그것에 대해 틀릴 수 있지만 2011 년 마지막으로 터치 한 게임 코드를 업데이트 할 때 지금 나에게 보이는 방법입니다).

기본적으로 트릭은 GLSurfaceView를 뷰 계층에서 활동의 onPause ()에서 분리하는 것입니다. onPause ()가 실행되는 시점에서 뷰 계층 구조에 없으므로 컨텍스트가 절대로 파괴되지 않습니다.

따라서 활동의 onPause ()는 다음과 같아야합니다.

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

그리고 당신은 계층 구조에 GLSurfaceView를 복원 하지 onResume (에서)하지만 onWindowFocusChanged ()에서 :

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

GLSurfaceView의 onPause () 및 onResume ()을 호출하지 않으며 공식 SDK GLSurfaceView이므로 해킹 된 대체 버전이 필요하지 않습니다.


실제로이 방법은 효과가없는 것 같습니다. Chris Pruett가 Unity와 함께 사용했는데이 해결 방법이 기본 프로젝트에서 작동하지 않을 수 있습니까? 그러나 GLView.onPause ()를 호출하지 않으면 작동하는 것 같습니다!? 이것을 확인할 수있는 다른 사람들이 있습니까?
sjkm

그것은 Android 2.2 OpenGl ES 2를 목표로 저에게 효과적이었습니다. 다른 장치에서 어떻게 작동하는지 잘 모르겠습니다. LG G2 D802 전화가 있습니다. 이것이 일반적인 해결책인지 아는 사람이 있습니까?
Pixel

7

<rant> 나는이 문제에 대해 많은 시간을 보냈고 많은 다른 솔루션을 시도했지만 오늘까지 일한 적이 없었습니다. 이것은 내가 본 것 중 가장 끔찍한 디자인 결정 중 하나라고 생각합니다. 정말 놀랐습니다. </ rant>

따라서 해결책은 eglContext 멤버를 위로 이동하여 정적 (전역)으로 만들어서 파괴되지 않도록 한 다음 다시 작성하기 전에 null인지 여부를 확인해야합니다.

지금까지이 솔루션은 우리에게 효과가있는 것으로 보이며 2005 장치에서 문제가 발생하더라도 신경 쓰지 않습니다.


4

벌집 API를 사용하십시오. OGL 컨텍스트를 유지하는 옵션이 있습니다. 그렇지 않으면 컨텍스트를 다시로드해야합니다. 어렵거나 고통스럽지 않습니다.

두 가지 경우 (Android 2.1)가 있음을 이해해야합니다.

  • 화면 일시 중지 : 응용 프로그램이 항상 전면에 있습니다 => 해킹 가능
  • 응용 프로그램 일시 중지 : 다른 전면 응용 프로그램이 있습니다 => 해결책 없음

참고 : 오래된 안드로이드 GPU는 다중 컨텍스트를 지원하지 않습니다. 따라서 다른 응용 프로그램으로 전환하면 사용 가능한 솔루션이 없으면 opengl 컨텍스트가 손실됩니다 (화면 일시 중지시 컨텍스트를 유지하기 위해 해킹 할 수 있음).

참고 2 : HoneyComb 기능은 setPreserveEGLContextOnPause입니다.


1
컨텍스트를 쉽게 다시로드하도록 설계되지 않은 Android NDK로 C ++ 게임을 포팅 중이므로 적어도 다소 어렵습니다. 문제를 제쳐두고, 텍스처를 다시로드하면 다른 장치 (iPhone, PSP, DS 등)에는없는 지연이 생길 수 있습니다. 허니컴 수정 사항을 듣고 기뻐하지만 불행히도 우리는 2.1 이상을 지원해야합니다.
Nick Gotch

1
이것은 그의 질문에 전혀 답하지 않습니다.
notlesh

1
당신이 이해하지 않으면, 당신은 그것을 할 수 없습니다.
엘리스

2

여기에있는 답변 중 일부는 Android에서 OpenGL ES를 초기에 사용하는 데 합리적입니다. 첫 번째 GLES 장치는 단일 컨텍스트 만 지원하므로 GLSurfaceView는 적극적으로 상태를 삭제하도록 설계되었습니다. 그렇지 않으면 GLSurfaceView를 설득하는 것이 쉽지 않습니다.

최신 버전의 Android (아마도 GLES 2.x를 사용하는 모든 버전)의 경우 가장 좋은 대답은 일반 SurfaceView를 사용하고 자체 EGL 및 스레드 관리를 수행하는 것입니다. EFI 컨텍스트를 작성하고 제거하기위한 간단한 클래스 라이브러리를 포함하여 Grafika 에서 일반 SurfaceView와 함께 사용되는 GLES의 여러 예제를 찾을 수 있습니다 .

앱이 백그라운드로 갈 때 상태를 언로드하는 것이 좋습니다.하지만 앱이 여전히 포 그라운드에 있지만 GLSurfaceView를 호스팅하는 액티비티가 전환 된 Chris Pruett의 예제는 찢어 질 가치가 없습니다. 상황에 따라

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.