코딩하기 좋은날
Android Graphics 번역 6편 - SurfaceView와 GLSurfaceView 본문
출처: https://source.android.com/devices/graphics/arch-sv-glsv
SurfaceView
SurfaceView는 다른 View들과 동일한 종류의 인자를 받으므로, SurfaceView의 위치와 크기를 지정하거나 주위에 다른 UI요소들을 넣을 수 있다. SurfaceView가 rendering 할 때가 되면, 컨텐츠들은 완전히 투명하게 된다.
GL context 또는 media decoder와 같은 외부 buffer 소스로 rendering할 때 buffer를 화면에 표시하려면 buffer 소스에서 buffer를 복사해야 한다. SurfaceView를 사용하면 그렇게 할 수 있다.
SurfaceVIew의 View컴포넌트가 시각화 되려고 할때, 프레임워크는 SurfaceControl 에게 SurfaceFlinger가 새 Surface를 생성하도록 요청한다. Surface가 생성되거나 소멸될 때 callback을 수신하려면 SurfaceHolder 인터페이스를 사용해야 한다. default로 생성된 Surface는 app UI Surface 뒤에 배치되며, Z-ordering을 재정의 해서 위에 배치하도록 할 수 있다.
SurfaceView를 사용한 rendering은 Camera API 또는 OpenGL ES context로 rendering할 때와 같이 별도의 Surface으로 rendering해야 하는 경우에 유용하다.
이 Surface에 무엇을 rendering 하던지간에, App이 아니라 SurfaceFlinger에 의해 합성이 될 것이다.(SurfaceView는 App과는 별도의 Window영역으로 동작한다.) 이것이 Surface의 진정한 장점이다. 얻게 된 Surface는 별도의 thread나 process에 의해 rendering 될 수 있고, app UI에 의해 수행되는 rendering에서 격리 될 수 있으며, buffer들이 직접 SurfaceFlinger에 전달되게 한다. 그러나 UI thread의 동작 전부를 무시할 수는 없다. SurfaceView로 rendering한 후 UI thread를 사용하여 activity lifecycle을 조정하고 필요한 경우 View의 크기 또는 위치를 조정한다. 그런 다음 Hardware Composer는 앱 UI와 다른 레이어를 혼합한다.
SurfaceView and the activity lifecycle
SurfaceView를 사용할 때, Surface는 UI thread가 아닌 다른 thread에서 rendering 된다. SurfaceView가 있는 Activity의 경우 두 개의 개별적이지만 상호 의존적인 state machine이 있다.
- App onCreate / onResume / onPause
- Surface created / changed / destroyed
Activity가 시작되면 다음의 순서로 callback을 받게 된다.
- onCreate()
- onResume()
- surfaceCreated()
- surfaceChanged()
만약 back()키를 누른다면 다음의 callback을 받을 것이다.
- onPause()
- surfaceDestroyed()
만약 화면을 회전한다면 isFinishing()을 체크함으로써 빠른 restart를 알려 줄 수 있다. Activity가 아주 빠르게 start/stop 된다면 onPause()이후에 surfaceCreated()가 호출 될 수 있다.
만약 전원 버튼을 눌러 화면을 끈다면 surfaceDestroyed() 없이 onPause()만 받을 것이다. Surface는 이 상황에서 active한 상태로 남아있으며, 끊임없이 rendering을 하고 있을 것이다.
스레드의 수명은 화면이 비어 있을 때 발생하려는 작업에 따라 Surface나 Activity에 연결될 수 있다. thread는 activity start/stop 또는 Surface create/destroy 시 start/stop할 수 있다.
activity start/stop에서 thread를 start/stop하는 것은 앱 lifecycle과 잘 동작한다. onResume()에서 renderer thread를 시작하고 onStop()에서 중지한다. thread를 생성 및 구성할 때 Surface가 이미 존재하는 경우도 있고 존재하지 않는 경우도 있다(예: 전원 버튼으로 화면을 전환한 후에도 여전히 활성 상태임). thread를 초기화하기 전에 Surface가 생성될 때까지 기다려야 한다. Surface가 재생성 되지 않는 경우에는 SurfaceCreated()콜백을 받을 수 없으므로 Surface상태를 쿼리하거나 캐시한다음 rendere thread로 전달해야 한다.
note: thread간 객체를 전달할 때 주의해라. Surface나 SurfaceHolder를 넘겨야 하는 경우 multicore 시스템에서 발생할수 있는 문제를 피하기 위해 Handler message를 이용하는 것이 가장 좋다.
Surface create/destroy에서 thread start/stop를 하는 것은 Surface와 renderer가 논리적으로 얽혀 있기 때문에 잘 작동한다. 화면이 비어 있을 때 rendering을 중지하고 빈 화면이 해제될 때 다시 시작되도록 하려면 Choreographer에게 frame draw callback 호출을 중지하도록 지시하면 된다.
GLSurfaceView
- OpenGL rendering을 표시하기 위해 dedicated surface를 사용하는 SurfaceView
- 안드로이드 View 시스템에 합성될 수 있는 특별한 메모리 조각인 Surface를 관리한다.
- OpenGL이 surface에 rendering 가능하도록 하는 EGL display를 관리한다.
- 실제로 rendering을 하는 user-provided Renderer object를 받는다.
- 전용 thread에서 rendering하여 UI 스레드에서 렌더링 성능을 분리한다.
- on-demand and continuous rendering(default mode) 지원
- 일반적인 View와 달리, drawing은 GLSurfaceView에 등록된 별도의 Renderer가 처리한다.(setRenderer)
- default로 GLSurfaceView는 Pixelformat.RGB_888 포맷 surface를 만든다. 만약 투명 surface가 필요하다면 getHolder().setFormat(PixelFormat.TRANSULCENT)를 호출해야 한다.
- 액티비티 라이프 사이클에 따라, onPause, onResume을 호출해주어야 한다.
'Android' 카테고리의 다른 글
Jetpack Compose Phases(컴포즈의 단계들) (2) | 2023.11.30 |
---|---|
Android Graphics 번역 7편 - SurfaceTexture와 TextureView (0) | 2022.07.24 |
Android Graphics 번역 5편 - Surface와 SurfaceHolder, canvasRendering (0) | 2022.07.05 |
Android Graphics 번역 4편 - SurfaceFlinger와 Hardware composer (0) | 2022.07.05 |
Android Graphics 번역 3편 - BufferQueue and Gralloc (0) | 2022.07.05 |