[Android] Systrace를 사용하여 SurfaceFlinger 동작 원리 확인하기

Android System Trace (Systrace (출처1))를 사용하여 GPU가 Rendering 한 결과 이미지를 SurfaceFlinger을 통해서 Display 되는 순서를 확인하는 방법에 대해서 정리하였다. Systrace를 사용하여 순서를 확인하기 전에 Android에서 Producer, Consumer, BufferQueue에 대한 이해가 필요하다. 솔직히 완전히 이해하진 못하지만, 간단히 이해한 내용을 정리하였다. 다음에 알게 되는 내용을 추가하거나,  또는 잘못된 내용을 찾게 되면 수정할 계획이다.


그림 1: Producer/Buffer Queue/Consumer 동작 순서 (출처 2)

나의 경우 Game을 Rendering 하여 결과를 SurfaceFlinger 연산을 거쳐서 Display 되는 것에만 관심이 있다. 그래서 GPU를 Producer라고 정의하고, Display 되는 부분은 Consumer로 정의하였다. Android는 Producer가 생성한 이미지를 BufferQueue를 통하여 Consumer로 전달된다 (출처 2, 3). 그림 1은 Producer, BufferQueue, Consumer의 관계를 보여준다. 가장 먼저 Producer(GPU)가 dequeueBuffer()를 사용하여 Buffer를 받게 된다. Producer가 Buffer를 받으면 GPU는 Rendering 연산을 수행하여 이미지를 생성한다. Rendering 연산 결과(이미지)가  Buffer에 저장되면 queueBuffer()을 사용하여 Buffer를 Release 한다.

MK: 정확한 bufferQueue 동작 원리는 모르겠다. 그래서 Release라는 단어를 사용했다. BufferQueue는 단순 클래스로 Producer와 Consumer을 연결해주는 역활만 수행하는 것 같다.

그림 2: UnityGfxDevice – dequeueBuffer/queueBuffer 동작 순서

그림 2는 Systrace 결과이다. UnityGfxDevice(GPU로 추정)가 dequeueBuffer()와 queueBuffer()을 순서대로 사용하고 있는 것을 확인할 수 있다. 그림2는 요즘 개인적으로 즐기는 Ballz라는 게임을 Systrace를 사용하여 얻은 결과이다.

MK: Systrace 결과물을 보면 dequeueBuffer()와 queueBuffer()의 사이가 너무 짧아서 실제로 GPU의 동작 시간이 짧은건지 아니면 dequeueBuffer()가 GPU와 동시에 실행되는 게 아닌 건지 의심스럽기는 하다. 이 부분은 다음에 더 알게 되면 수정을 할 계획이다.

다음은 Consumer(SurfaceFlinger)가 Buffer를 Display 하는 순서를 정리하였다. SurfaceFlinger는 여러 개의 Buffer(이미지 결과물)를 받아서 하나의 이미지로 생성하여 Display 하는 로직이다. 여러 개의 Buffer란 Game Rendering 결과, Status Bar(배터리 표시되는 부분), Navigation Bar(홈 버튼이 표시되는 부분) 등을 의미한다. 각 Buffer(Layer)는 독립적으로 업데이트가 진행된다. Status Bar, Navigation Bar의 경우 System Process가 Rendering을 수행한다 (출처 4).

그림 3: SurfaceFlinger – acquireBuffer/releaseBuffer 동작 순서

그림 1과 같이 SurfaceFlinger(Consumer)은 acquireBuffer()을 사용해서 Buffer를 받게 된다. SurfaceFlinger은 Buffer를 받아서 이미지를 하나로 합치는 작업(Composite)을 수행한다.  Display는 SurfaceFlinger에서 Composite한 결과를 출력한다. Display 결과 출력후 releaseBuffer()를 사용하여 Buffer를 Release 한다. 그림 3은 Systrace에서 SurfaceFlinger가 acquireBuffer()와 releaseBuffer()을 사용하는 부분을 보여준다. 아마 중간에 있는 많은 부분이 Composite 연산을 수행하는 과정으로 추측된다.

추가로 그림 3에 보면 왼쪽에 SurfaceView(보라색)라는 부분이 존재한다. 이 부분에서 계단식으로 오르락내리락 반복하는 것을 확인할 수 있다. 이 부분이 Buffering에 이미지가 저장된 개수를 의미한다. 안드로이드의 경우 Triple Buffering을 사용하기 때문에 총 3개의 Buffer가 존재해야 한다 (출처 6). 하지만,  Systrace 결과에서는 2개만 보이는데 아마 1개는 SurfaceFlinger가 Display를 위해서 점유하고 있기 때문에 2개가 Max인 것 같다.  Producer 사이드에서 queueBuffer()를 수행하면 다시 올라가는 계단이 되는 것을 확인할 수 있다. 반대로 SurfaceFlinger가 acquireBuffer()를 수행하면 계단이 내려가는 형태를 보인다.

출처

  1. https://source.android.com/devices/tech/debug/systrace
  2. https://www.charlezz.com/?p=1025
  3. https://source.android.com/devices/graphics/arch-bq-gralloc
  4. https://source.android.com/devices/graphics/arch-sf-hwc
  5. https://www.youtube.com/watch?v=1xTl9o_agGc&list=PLOU2XLYxmsILVTiOlMJdo7RQS55jYhsMi&index=47&t=0s
  6. https://mkblog.co.kr/2018/07/24/gpu-double-buffering-triple-buffering-and-vsync/

Leave a Comment