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로만 구현 가능)
'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 |