android graphic architecture

BufferQueue

그래픽 데이터의 생산자와 소비자를 연결 수켜주는 역할을 한다. (프로세스가 서로 달라도 된다.)

생산자는 버퍼 특징을 기술한다.

  • 높이, 넓이, 픽셀포맷, 플래그 등

Data Flow

  • dequeBuffer
  • 생상자 버퍼 채움
  • queueBuffer
  • 소비사 버퍼 획득
  • acquireBuffer
  • 버퍼 활용
  • releaseBuffer

gralloc HAL

allock함수를 이용해 버퍼를 할당한다.

  • 넓이,높이,픽셀포맷, 용도 플래그가 인자

예) RGBA8888 픽셀 포멧의 경우 R->G->B->A 순서로 4바이트 버퍼를 생성한다.

SurfaceFlinger

그래픽 데어터 버퍼를 받고 Display로 보내는 목적

  • 앱 포어그라운드 -> 윈도우매니저 -> surfaceflinger -> draw 요청

BufferQueue의 소비자 처럼 동작한다.

  • 생산자 -> 바인더객체 -> 윈도우매니저 -> 앱 -> surfaceflinger 프레임전송
    showSoftInput
    해당 기능은 디스플레이가 버퍼 처리가능할 때 작동이 시작된다.

프레임렌더링 구조

생산자 -> 버퍼를 채움 -> 버퍼큐 채움 -> surfacelinger 쪽으로 이동 -> HWcomposer로 다음 frame 전송 -> HWComposer는 Systemui(상태바등)와 bufferqueu 정보를 합쳐서 화면에 표시함 (VSYNC 발생 시 frame 그림)

app -> MediaCodec -> raw데이터 버퍼 또는 Surface제공

Surface

BufferQueue의 생산자 역할

SurfaceFlinger는 Bufferqueue의 소비자 역할

dumpsys SurfaceFlinger명령을 통해 레이어와 연관된 버퍼 정보를 확인 가능

Build configuration: [sf] [libui] [libgui]
Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]
DispSync configuration: app phase 0 ns, sf phase 0 ns, present offset 0 ns (refresh 16666666 ns)
Visible layers (count = 6)
+ LayerDim 0x9203b000 (DimLayer)
  Region transparentRegion (this=0x9203b178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x9203b008, count=1)
    [  0,   0,   0,   0]
      layerStack=   0, z=        0, pos=(0,0), size=(  16,  16), crop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000001, tr=[1.00, 0.00][0.00, 1.00]
      client=0x954391c0
      format= 0, activeBuffer=[   0x   0:   0,  0], queued-frames=0, mRefreshPending=0
            mTexName=4 mCurrentTexture=-1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1x1], default-format=1, transform-hint=00, FIFO(0)={}
+ LayerDim 0x92023000 (DimLayer)
  Region transparentRegion (this=0x92023178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x92023008, count=1)
    [  0,   0,   0,   0]
      layerStack=   0, z=        0, pos=(0,0), size=(  16,  16), crop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000001, tr=[1.00, 0.00][0.00, 1.00]
      client=0x954391c0
      format= 0, activeBuffer=[   0x   0:   0,  0], queued-frames=0, mRefreshPending=0
            mTexName=5 mCurrentTexture=-1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1x1], default-format=1, transform-hint=00, FIFO(0)={}
+ LayerDim 0x963ba000 (DimLayer)
  Region transparentRegion (this=0x963ba178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x963ba008, count=1)
    [  0,   0,   0,   0]
      layerStack=   0, z=        0, pos=(0,0), size=(  16,  16), crop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000001, tr=[1.00, 0.00][0.00, 1.00]
      client=0x954391c0
      format= 0, activeBuffer=[   0x   0:   0,  0], queued-frames=0, mRefreshPending=0
            mTexName=7 mCurrentTexture=-1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1x1], default-format=1, transform-hint=00, FIFO(0)={}
+ LayerDim 0x92021000 (DimLayer)
  Region transparentRegion (this=0x92021178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x92021008, count=1)
    [  0,   0,   0,   0]
      layerStack=   0, z=        0, pos=(0,0), size=(  16,  16), crop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000001, tr=[1.00, 0.00][0.00, 1.00]
      client=0x954391c0
      format= 0, activeBuffer=[   0x   0:   0,  0], queued-frames=0, mRefreshPending=0
            mTexName=8 mCurrentTexture=-1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1x1], default-format=1, transform-hint=00, FIFO(0)={}
+ Layer 0x92019000 (com.example /com.example.MainActivity)
  Region transparentRegion (this=0x92019178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x92019008, count=1)
    [  0,   0, 1920, 1080]
      layerStack=   0, z=    21005, pos=(0,0), size=(1920,1080), crop=(   0,   0,1920,1080), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000002, tr=[1.00, 0.00][0.00, 1.00]
      client=0x96074440
      format= 1, activeBuffer=[1920x1080:1920,  1], queued-frames=0, mRefreshPending=0
            mTexName=9 mCurrentTexture=1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=1, transform-hint=00, FIFO(0)={}
             [00:0x9606d980] state=FREE    , 0x96087380 [1920x1080:1920,  1]
            >[01:0x9606da20] state=ACQUIRED, 0x96087440 [1920x1080:1920,  1]
             [02:0x9606dac0] state=FREE    , 0x96087500 [1920x1080:1920,  1]
+ Layer 0x9203d000 (FocusedStackFrame)
  Region transparentRegion (this=0x9203d178, count=1)
    [  0,   0,   0,   0]
  Region visibleRegion (this=0x9203d008, count=1)
    [  0,   0,   0,   0]
      layerStack=   0, z=    21006, pos=(0,0), size=(   1,   1), crop=(   0,   0,  -1,  -1), isOpaque=0, invalidate=0, alpha=0x4d, flags=0x00000001, tr=[1.00, 0.00][0.00, 1.00]
      client=0x954391c0
      format= 1, activeBuffer=[   0x   0:   0,  0], queued-frames=0, mRefreshPending=0
            mTexName=3 mCurrentTexture=-1
            mCurrentCrop=[0,0,0,0] mCurrentTransform=0
            mAbandoned=0
            -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1x1], default-format=1, transform-hint=00, FIFO(0)={}
Displays (1 entries)
+ DisplayDevice: Built-in Screen
   type=0, hwcId=0, layerStack=0, (1920x1080), ANativeWindow=0x96225408, orient= 0 (type=00000000), flips=159, isSecure=1, secureVis=0, powerMode=2, activeConfig=0, numLayers=1
   v:[0,0,1920,1080], f:[0,0,1920,1080], s:[0,0,1920,1080],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]]
mAbandoned=0
-BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=1, transform-hint=00, FIFO(0)={}
 [00:0x9606d3e0] state=FREE    , 0x96086780 [1920x1080:1920,  1]
 [01:0x9606d480] state=FREE    , 0x96086840 [1920x1080:1920,  1]
>[02:0x9606d520] state=ACQUIRED, 0x96086900 [1920x1080:1920,  1]
SurfaceFlinger global state:
EGL implementation : 1.4 Midgard-"r8p0-02rel0"
 EGL_ANDROID_image_native_buffer EGL_ANDROID_recordable EGL_ANDROID_native_fence_sync EGL_ANDROID_framebuffer_target EGL_ANDROID_blob_cache EGL_KHR_partial_update EGL_KHR_config_attribs EGL_KHR_image EGL_KHR_image_base EGL_KHR_fence_sync EGL_KHR_wait_sync EGL_KHR_gl_colorspace EGL_KHR_get_all_proc_addresses EGL_IMG_context_priority EGL_KHR_gl_texture_2D_image EGL_KHR_gl_renderbuffer_image EGL_KHR_create_context EGL_KHR_surfaceless_context EGL_KHR_gl_texture_cubemap_image EGL_EXT_create_context_robustness
GLES: ARM, Mali-T720, OpenGL ES 3.1 v1.r8p0-02rel0.b25106f7a00abf0fd922cfe23b51206f
GL_EXT_debug_marker GL_ARM_rgba8 GL_ARM_mali_shader_binary GL_OES_depth24 GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_standard_derivatives GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_EGL_sync GL_OES_texture_npot GL_OES_vertex_half_float GL_OES_required_internalformat GL_OES_vertex_array_object GL_OES_mapbuffer GL_EXT_texture_format_BGRA8888 GL_EXT_texture_rg GL_EXT_texture_type_2_10_10_10_REV GL_OES_fbo_render_mipmap GL_OES_element_index_uint GL_EXT_shadow_samplers GL_OES_texture_compression_astc GL_KHR_texture_compression_astc_ldr GL_KHR_texture_compression_astc_hdr GL_KHR_debug GL_EXT_occlusion_query_boolean GL_EXT_disjoint_timer_query GL_EXT_blend_minmax GL_EXT_discard_framebuffer GL_OES_get_program_binary GL_OES_texture_3D GL_EXT_texture_storage GL_EXT_multisampled_render_to_texture GL_OES_surfaceless_context GL_OES_texture_stencil8 GL_EXT_shader_pixel_local_storage GL_ARM_shader_framebuffer_fetch GL_ARM_shader_framebuffer_fetch_depth_stencil GL_ARM_mali_program_binary GL_EXT_sRGB GL_EXT_sRGB_write_control GL_EXT_texture_sRGB_decode GL_KHR_blend_equation_advanced GL_KHR_blend_equation_advanced_coherent GL_OES_texture_storage_multisample_2d_array GL_OES_shader_image_atomic GL_EXT_robustness GL_EXT_texture_border_clamp GL_OES_texture_border_clamp GL_EXT_texture_cube_map_array GL_OES_texture_cube_map_array GL_OES_sample_variables GL_OES_sample_shading GL_OES_shader_multisample_interpolation GL_EXT_shader_io_blocks GL_OES_shader_io_blocks GL_EXT_gpu_shader5 GL_OES_gpu_shader5 GL_EXT_texture_buffer GL_OES_texture_buffer GL_EXT_copy_image GL_OES_copy_image
  Region undefinedRegion (this=0x960b352c, count=1)
    [  0,   0,   0,   0]
  orientation=0, isDisplayOn=1
  last eglSwapBuffers() time: 7657.042000 us
  last transaction time     : 180.167000 us
  transaction-flags         : 00000000
  refresh-rate              : 60.000002 fps
  x-dpi                     : 159.895004
  y-dpi                     : 160.421005
  gpu_to_cpu_unsupported    : 0
  eglSwapBuffers time: 0.000000 us
  transaction time: 0.000000 us
VSYNC state: disabled
  soft-vsync: disabled
  numListeners=9,
  events-delivered: 297
    0x9544c038: count=-1
    0x9544c060: count=-1
    0x9544c088: count=-1
    0x9544c0b0: count=-1
    0x96038b78: count=-1
    0x96038ba0: count=-1
    0x96038bf0: count=-1
    0x96038f38: count=-1
    0x96038f60: count=-1
h/w composer state:
  h/w composer present and enabled
Hardware Composer state (version 01010000):
  mDebugForceFakeVSync=0
  Display[0] configurations (* current):
    * 0: 1920x1080, xdpi=159.895004, ydpi=160.421005, refresh=16666666
  numHwLayers=2, flags=00000000
    type   |  handle  | hint | flag | tr | blnd |   format    |     source crop (l,t,r,b)      |          frame         | name
-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------
       HWC | 96087440 | 0000 | 0000 | 00 | 0100 | RGBA_8888   |      0,      0,   1920,   1080 |    0,    0, 1920, 1080 | com.example /com.example
 FB TARGET | 96086900 | 0000 | 0000 | 00 | 0105 | RGBA_8888   |      0,      0,   1920,   1080 |    0,    0, 1920, 1080 | HWC_FRAMEBUFFER_TARGET
Allocated buffers:
0x96086780: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00001a00
0x96086840: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00001a00
0x96086900: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00001a00
0x96087380: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00000b00
0x96087440: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00000b00
0x96087500: 8100.00 KiB | 1920 (1920) x 1080 |        1 | 0x00000b00
Total allocated (estimate): 48600.00 KB

Canvas Rendering

  • Skia Graphics Library : 렌더링 로우레밸 처리

Skia는 바이트를 버퍼의 형태로 구성기 위해 그리고 멀티 클라이언트에 의한 동시 업데이트를 방지하기 위해, 버퍼 액세스 락을 사용한다.

  • lockCanvas() : 버퍼에 락을 걸고 드로잉을 위한 Canvas를 리턴

  • unlockCanvasAndPost() :버퍼에 락을 해제 하고 compositor로 전달

하드웨어 가속 Canvas API (OpenGL ES 지원을 위함)

  • View onDraw Canvas : 하드웨어 가속 가능
  • APP이 직접 lockCanvas()를 통해 캠버스(surface)를 얻어 오는 것과는 다름 : 사용자 lock Canvas 기반 CPU랜더러는 GLES로 Surface드로잉을 할 수 없거나 비디오 디코더에 출력된 프레임을 보낼 수 없다.
  • Canvas를 사용하지 않고 Surface에 직접 드로잉 하는 주요 방법은 OpenGL ES를 사용하면 됨

SurfaceHolder

surface와 관련된 작업은 surfaceHolder와 surfaceView가 필요함

  • surface : compositor에 관리 되는 버퍼
  • surfaceholder : 앱에 의해 관리되고 surface의 크기나 포맷같은 고수준 정보를 관리

view와 관련된 작업은 surfaceholder를 포함하고, MediaCodec같은 API들은 surface상에서 동작한다. Surface는 surfacehoder를 통해 얻을 수 있다. surface의 설정 정보들을 얻고자 하면 surfacehoder를 통해 구하면 된다.

SurfaceView

Surface + View

surfaceview -> 투명 -> view컴포넌트 시각화 시작 -> windowmanager -> sufaceflinger가 surface생성 요청

비동기적 작동으로 surface생성 완료시 callback처리 해야한다

새로운 sruface는 보이지 않는 영역에 생김, z ordering을 통해 상위로 올려야함

view 펀칭을 통한 화면 제공 방식이다. "surfaceview -> window -> surface -> 사용자 눈" 이라고 했을때 window에 fixed된 창을 뚫는 방식이다.

이런 방식으로 인해 SurfaceView는

  • transformation, animation 등의 처리가 불가능하다.

SurfaceTexture

Surface + GLES Texture 조합

SurfaceTexture생성 -> BufferQueue 생성 -> 생상자 SurfaceTexture 생성 -> Bufferqueue 인큐 -> onFrameAvailable() 통지 -> updateTexImage 메서드 호출 -> bufferqueue 버퍼 얻음

  • getTimestamp() : timestamp 정보
  • getTransformMatrix : 가자 최근 호출된 updateTexImage()메서드 설정된 변환 행렬()
  • 변환행렬 : 잘못된 소스데이터를 보정 가능
  • timestamp : 카메라 코드에 의해 설정되며 프레임이 캡처될때 기준으로 리턴된다.

surfaceview와는 다르게 view 그룹의 하이어러키에 포함된다. (surfaceview의 rendering은 다른 view 그룹의 랜더링과 독립으로 처리 되는것으로 보인다.) 그렇기에 surfacetexture는

  • transformation, animation 처리 등이 가능하다
  • 그러나 memory 사용량이 상대적으로 높고, 해당 surface의 redraw가 해당 그룹 전체의 redraw에 영향을 줄수 있다.
  • video player를 개발하게 되면 사실상 surfacetexture를 사용할 수 밖에 없는데 fullscreen mode가 전제 된다면 surfaceview를 사용하는 것이 좋다(drm contents는 surfaceview 사용 권장)

해당 컴포넌트는 반듯이 하드웨어 렌더링을 지원해야 한다.

TextureView

View + SurfaceTexture

TextureView는 SurfaceTexture를 wrap하고 있음

  • SurfaceTexture Callback 응답처리, 신규 버퍼 획득 처리 역할
  • View invalidate 요청 : 신규 버퍼 수신 시
  • 장점 : View 계층 구조에 소속되어 동작, 다른 View와 동일, API 임의 변환 수행 및 비트맵을 컨텐츠로 로드가능
  • 단점 : 합성 단계 성능, View 합성이 GLES로 수행되고 다른 View 요소들의 리드로잉을 발생 시킴. Video 처리 등을 위해서는 SurfaceView가 더 좋은 성능을 제공 (DRM Contents는 SurfaceView로만 구현 가능)
728x90
반응형

'Android' 카테고리의 다른 글

AOSP system app install  (0) 2020.08.20
Android Grafika Texture Surface  (0) 2020.03.27
android memory leak 처리  (0) 2020.03.27
android ART GC Log  (0) 2020.03.27
android keyboard show on the web  (0) 2020.03.27