概述
要理解Android的圖形架構(gòu),我們需要先理解window的概念。維基百科中給window的定義是:Window是圖形用戶界面(GUI)系統(tǒng)中顯示器上一個(gè)單獨(dú)的視圖區(qū)域(可以想象你電腦桌面上一個(gè)個(gè)窗口)。因此,Android圖形架構(gòu)的就是把各個(gè)應(yīng)用創(chuàng)建的一個(gè)個(gè)window組合顯示到顯示屏上的架構(gòu)。
首先我們要理解Android系統(tǒng)中以下概念:
Window:代表顯示器上一個(gè)單獨(dú)的視圖區(qū)域的對(duì)象。它由WindowManager控制。由view構(gòu)成。這些view構(gòu)成一個(gè)View Hierarchy結(jié)構(gòu)。而這個(gè)View Hierarchy被渲染到WindowFlinger創(chuàng)建給Window的Surface上。
View:代表和用戶交互組件的基礎(chǔ)模塊。一個(gè)view占據(jù)屏幕上的一個(gè)矩形區(qū)域,并負(fù)責(zé)這個(gè)區(qū)域的圖形繪制和交互事件。Android中每個(gè)window的view構(gòu)成一個(gè)View Hierarchy結(jié)構(gòu)。
Surface:由SurfaceFlinger創(chuàng)建給WindowManager,并被WindowManager交給Window用來(lái)繪制window中view的內(nèi)容。這些內(nèi)容可以由view用canvas繪制,或者采用OpenGL ES等方法。它是指java對(duì)象,c++對(duì)應(yīng)的對(duì)象是ANativeWindow。
Display:Android 系統(tǒng)支持一個(gè)內(nèi)置顯示器(手機(jī)或平板上內(nèi)置的顯示器)、一個(gè)外接顯示器(如通過(guò) HDMI 連接的電視屏幕)、若干個(gè)虛擬顯示器(由 APP 調(diào)用 DisplayManager#createVirtualDisplay 創(chuàng)建,app 需要提供 surface)。
簡(jiǎn)而言之,就是,Window中的view被繪制或渲染到Surface中,才能被顯示在Display上。如圖
那么,Window是怎么產(chǎn)生的呢?
每個(gè)Activity、DreamService、Dialog、MediaController、Toast或者自定義View在創(chuàng)建時(shí)都會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的Window。這些Window可以設(shè)置父子關(guān)系,如一般的Dialog會(huì)是它所屬Activity的子Window。這些子Window會(huì)擁有自己?jiǎn)为?dú)的Surface。
多個(gè)Window組合在一起就構(gòu)成了界面,也就是多個(gè)Surface的內(nèi)容組合在一起就構(gòu)成了界面的顯示,其中Surface的組合則是由SufaceFlinger根據(jù)各個(gè)Window的z-order之類的元數(shù)據(jù)組合的,SurfaceFlinger組合之后確定了顯示屏上哪個(gè)Window需要顯示、顯示多少、顯示在屏上哪個(gè)位置等,然后再把組合后的數(shù)據(jù)傳給圖形硬件抽象層(HAL)。如圖
Android graphics components
上面提到,View用Canvas把內(nèi)容繪制到Surface上,然后顯示在界面上,那么被繪制到Surface上的內(nèi)容是怎么顯示的呢?
如上圖(Surface 如何被渲染)中顯示的,它們通過(guò)Buffer Data傳遞被繪制的內(nèi)容。App通過(guò)Canvas或Media Player或Camera Preview或OpenGL ES生產(chǎn)Graphics Data并渲染到Surface,而SurfaceFlinger把這些Data組合然后通過(guò)Hardware Composer顯示。如圖:
簡(jiǎn)單來(lái)說(shuō),就是app生產(chǎn)graphics data,然后SurfaceFlinger合成組合所有的graphics data然后傳遞給Hardware Composer顯示。
其中,graphic data稱為Buffer,生產(chǎn)這些graphic data的Canvas、Media Player、Camera Preview等稱為圖形流生產(chǎn)方(Image Stream Producers)。而合成組合這些graphic data的SurfaceFlinger或OpenGL ES apps則稱為圖形流消耗方(Image Stream Consumers)。這些graphic data最后通過(guò)HWC(Hardware Composer)顯示在顯示器上。其中一個(gè)graphic data稱為Buffer,它們組成BufferQueue。
BufferQueue:BufferQueue是一個(gè)結(jié)合了buffer pool和隊(duì)列的數(shù)據(jù)結(jié)構(gòu),它使用Binder IPC在進(jìn)程間傳遞buffers。BufferQueue的生產(chǎn)方調(diào)用IGraphicBufferProducer(SurfaceTexture的一部分)接口來(lái)生成graphic buffers。而它的消耗方和GL Consumer一起消耗它并把它渲染到Surface。
SurfaceFlinger & WindowManager
SurfaceFlinger: accepts buffers, composes buffers, and sends buffers to the display. (接收并合成buffers,然后把它們發(fā)送給display顯示。)
WindowManager: provides SurfaceFlinger with buffers and window metadata, which SurfaceFlinger uses to composite surfaces to the display. (給SurfaceFlinger提供合成surfaces所需的buffers和window metadata。)
Layer: A combination of a surface and a SurfaceControl.?
Surface: contains the BufferQueue.?一個(gè)供Image Stream生產(chǎn)者和Image Consumer交換buffers的接口。它包含BufferQuene。使應(yīng)用可以渲染要顯示在屏幕上的Images。
SurfaceControl: contains the layer metadata like the display frame. It's uses to manipulate the appeareance of the app on the screen.?
Window:?containers for view objects. Window objects always backed by surface objects and controlled by WindowManager.?
Window metadata:?lifecycles, input and focus events, screen orientation, transitions, animations, position, transforms, z-order, and many other aspects of a window. Overseen by the WindowManager.
View: represents the basic building block for user interface components.?A view occupies a rectangular area on the screen and is responsible for drawing and event handling.
When an app comes to the foreground, it requestes buffers from WindowManager. WindowManager then sends all of the window metadata to SurfaceFlinger and requests a layer. SurfaceFlinger creates the layer and sends it to WindowManager. WindowManager then sends ther surface to the app, but keeps the SurfaceControl. 如圖:
VSYNC:?
APP 可以在任何時(shí)候提交buffers,但SurfaceFlinger僅僅在兩次display刷新中間被喚醒并接收buffers,這樣可減少內(nèi)存使用,并避免可見(jiàn)的屏幕撕裂(如果顯示內(nèi)容在刷新期間更新,就有可能發(fā)生)。
當(dāng)display處在兩次刷新中間時(shí),display會(huì)向SufaceFlinger發(fā)送VSYNC信號(hào)。VSYNC信號(hào)表示可以更新display且不用擔(dān)心產(chǎn)生撕裂。
SurfaceFlinger收到VSYNC信號(hào)后,會(huì)遍歷它的所有visible layers:如果該layer有新的buffer,獲取它;如果沒(méi)有,繼續(xù)使用舊的buffer;如果該layer沒(méi)有任何buffer,忽略它。當(dāng)所有l(wèi)ayer的buffer都被收集完后,SurfaceFlinger向Hardware Composer(HWC)詢問(wèn)這些layer的合成類型,如果得到的結(jié)果是客戶端合成,則合成。并把output buffer傳給HWC。
VSYNC信號(hào)可同步display pipeline(顯示管道)。display pipeline包含app渲染、SurfaceFlinger合成、HWC在顯示器上顯示圖片。VSYNC同步app因?yàn)橐_(kāi)始渲染而被喚醒的時(shí)間、SurfaceFlinger因?yàn)橐铣善聊欢粏拘训臅r(shí)間、和顯示器刷新周期。
SurfaceFlinger通過(guò)setVsyncEnable方法控制HWC是否生成VSYNC事件,當(dāng)HWC生成VSYNC事件后,會(huì)通過(guò)回調(diào)函數(shù)通知SurfaceFlinger。
在VSYNC事件發(fā)生時(shí),顯示器開(kāi)始顯示第N幀時(shí),SurfaceFlinger開(kāi)始合成第N+1幀,而app在處理等待的input事件并生成第N+2幀。
WinScope:
可用WinScope web分析WindowManager或SurfaceFlinger在window轉(zhuǎn)換期間和轉(zhuǎn)換后的狀態(tài)。
使用步驟:
1. 啟用
WindowManager:
adb shell cmd window tracing start
SurfaceFlinger:adb shell su root service call SurfaceFlinger 1025 i32 1
2. 停用
WindowManager:?adb shell cmd window tracing stop
SurfaceFlinger:adb shell su root service call SurfaceFlinger 1025 i32 0
3. 獲取pb文件
WindowManager:?adb pull /data/misc/wmtrace/wm_trace.pb wm_trace.pb
SurfaceFlinger:adb pull /data/misc/wmtrace/layers_trace.pb layers_trace.pb
4. 從 Android 源代碼庫(kù)中下載winscope.html:
curl 'https://android.googlesource.com/platform/prebuilts/misc/+/master/common/winscope/winscope.html?format=TEXT' | base64 -d > winscope.html
5. 打開(kāi)winscope.html
6. 點(diǎn)擊右上角的”O(jiān)PEN FILE“按鈕,選擇要打開(kāi)的pb文件,如圖:
這個(gè)trace里面有下面幾個(gè)部分:
Timeline?— 事件的時(shí)間軸。
Screen?— 顯示屏幕上所有的可見(jiàn)Window。
Hierarchy?— 包含系統(tǒng)已知的所有window,包括不可見(jiàn)的(這些window沒(méi)有buffer,但是對(duì)其子window有用)。可見(jiàn)window信息的末尾會(huì)帶有一個(gè)V標(biāo)簽。
Properties?— 顯示Hierarchy選中條目的具體信息。
WindowScope還可以從bug reports中讀取WindowManager和SurfaceFlinger的快照,bug reports以proto文件的形式存儲(chǔ)在proto文件夾中,用以下命令生成pb文件:
WindowManager:?adb exec-out dumpsys window --proto > window_dump.pb
SurfaceFlinger:?adb exec-out dumpsys SurfaceFlinger --proto > sf_dump.pb
Surface & SurfaceHolder
Layer:合成中最重要的單元。是Surface和SurfaceControl的結(jié)合。每個(gè)Layer都有一系列定義和其它layers交互的屬性,如Z-order等。
Surface:A surface is an interface for a producer to exchange buffers with a consumer. Surface objects enable apps to render images to be presented on screens.
SurfaceHolder:提供可以編輯和控制Surface的接口。大部分和view交互的組件都關(guān)聯(lián)一個(gè)SurfaceHolder來(lái)操作Surface,如SurfaceView。另外一些如MediaCodec之類的API,直接操作Surface。
View
構(gòu)建用戶界面的基礎(chǔ)元素,每個(gè)View占據(jù)屏幕上的一個(gè)矩形,并負(fù)責(zé)這個(gè)矩形區(qū)域的繪圖和事件處理。
Android的UI框架是一個(gè)view hierarchy結(jié)構(gòu),所有的UI元素經(jīng)過(guò)一系列的測(cè)量和布局放置在一個(gè)矩形區(qū)域內(nèi)。
View & Window & Surface
Window是圖形用戶界面(GUI)系統(tǒng)中顯示器上一個(gè)單獨(dú)的視圖區(qū)域。界面上的dialog、activity、status bar都有其對(duì)應(yīng)的Window,每個(gè)Window都有其對(duì)應(yīng)的View Hierarchy結(jié)構(gòu)。當(dāng)應(yīng)用到前臺(tái)時(shí),WindowManager會(huì)為每個(gè)Window獲取一個(gè)Surface,并把這個(gè)Surface給應(yīng)用,應(yīng)用在這塊Surface上用Canvas或者其它方法繪制它所屬Window中包含的View。在界面的兩次刷新中間時(shí),SurfaceFlinger會(huì)根據(jù)Z-order等信息合成系統(tǒng)中所有window的顯示區(qū)域,并最后渲染到屏幕上。
如果一個(gè)view要刷新,其實(shí)就是往它所屬window的Surface的BufferQuene中更新新的buffer內(nèi)容,等下次SurfaceFlinger遍歷時(shí)取出來(lái)重新合成。
簡(jiǎn)單的說(shuō)就是,Windows中的View要被渲染到Surface上才會(huì)被顯示。
SurfaceView
一般來(lái)說(shuō)一個(gè)View會(huì)和它所屬window中的view共用一塊Surface,但是SurfaceView擁有自己?jiǎn)为?dú)的Surface。當(dāng)SurfaceView所屬的window變成可見(jiàn)時(shí),framework會(huì)讓SurfaceControl向SurfaceFlinger申請(qǐng)一塊新的Surface給它。默認(rèn)情況下,這塊surface會(huì)被放在app其它UI surface的后面,如果要把它放在top可以override默認(rèn)的Z-order。
如果沒(méi)有SurfaceView,當(dāng)應(yīng)用需要使用如GL context(OpenGL ES context)或media decoder(Camera API)這類external buffer source進(jìn)行渲染時(shí),需要復(fù)制buffer source中的buffers,并把它們合成到window對(duì)應(yīng)surface中,才能讓它們顯示在屏幕上。而使用SurfaceView的話,SurfaceFlinger直接把source buffers合成到屏幕上。
SurfaceView的surface是BufferQueue的生產(chǎn)方,SurfaceFlinger是消耗方。
SurfaceTexture
SurfaceTexture是Surface和OpenGL ES(GLES) texture的組合。SurfaceTexture提供Surface給GLES渲染。
SurfaceTexture為消耗sources buffers的app持有一個(gè)BufferQueue。當(dāng)source buffers的生產(chǎn)方往BufferQueue里插入一個(gè)新buffer時(shí),onFrameAvailable() callback會(huì)被調(diào)用。然后app可以調(diào)用updateTexImage(),這個(gè)方法會(huì)釋放之前持有的buffer,從隊(duì)列中獲取生產(chǎn)方新插入的buffer,并進(jìn)行EGL調(diào)用使buffer可作為external texture供GLES使用。
SurfaceTexture使用external texture,external texture的優(yōu)點(diǎn)是能夠直接用BufferQueue中的數(shù)據(jù)進(jìn)行渲染。SurfaceTexutre在為external textures創(chuàng)建BufferQueues時(shí)會(huì)把消耗方的使用標(biāo)記設(shè)置為GRALLOC_USAGE_HW_TEXTURE,以確保GLES可以識(shí)別buffer中的數(shù)據(jù)。
TextureView
TextureView是SurfaceTexture和View的組合。
TextureView類里面封裝了一個(gè)SurfaceTexture,所以可以接收SurfaceTexture的回調(diào)和獲取可用buffer。當(dāng)buffer更新后,TextureView會(huì)觸發(fā)view的invalidate()方法請(qǐng)求重繪。
GLES可以通過(guò)把TextureView中的SurfaceTexture傳給創(chuàng)建EGL的調(diào)用來(lái)在TextureView上渲染。
如圖,表示一個(gè)應(yīng)用顯示Camera preview的數(shù)據(jù):
Camera的數(shù)據(jù)渲染到SurfaceTexture提供給它的Surface上,然后再把這些數(shù)據(jù)渲染到TextureView所屬Window的Surface上,或渲染到SurfaceView自己的Surface上。
SurfaceView or TextureView
SurfaceView有自己專用的Surface,而TextureView和它所屬Window上的view共用一塊Suface。
在 API 24 及更高版本中,建議使用SurfaceView而不是TextureView。
兩者功能類似并且都是 view hierarchy 中的一員。但是,它們實(shí)現(xiàn)方法不一樣。SurfaceView雖然和其它view共享window的參數(shù),但它的內(nèi)容在渲染時(shí)是透明的。
TextureView具有更好的alpha和rotation處理能力.
SurfaceView在合成視頻上分層的UI元素時(shí)性能更好:
1. 使用SurfaceView時(shí),系統(tǒng)會(huì)為SurfaceView提供一個(gè)單獨(dú)的合在層(layer),SurfaceFlinger將直接使用這個(gè)layer做為一個(gè)硬件疊加層和其它window的layer合成在一起。
2. 使用TextureView時(shí),UI工具通過(guò)GPU將TextureView中的內(nèi)容合成到它的view hierarchy中——當(dāng)TextureView內(nèi)容更新時(shí),可能會(huì)導(dǎo)致其它view的重繪,比如,放置在TextureView上面的view;而且因?yàn)樵趘iew的渲染完成后,SurfaceFlinger還要把它所屬的app UI layer和其它layer合成在一起,所以導(dǎo)致所有TextureView上的可見(jiàn)像素都被合成了兩次。
但TextureView在某些功能的實(shí)現(xiàn)上比SurfaceView要簡(jiǎn)單,比如縮放功能的實(shí)現(xiàn):縮放SurfaceView需要FrameLayout的自定義實(shí)現(xiàn),WindowManager需要告訴SurfaceFlinger新窗口的位置和大小等信息。而縮放TextureView只需要使用TextureView#setTransform()配置轉(zhuǎn)換矩陣。
EGLSurface & OpenGL ES
OpenGL ES:Open Graphics Libarary Embedded Systems,GLES,免費(fèi)的、用于在嵌入式和移動(dòng)系統(tǒng)如手機(jī)上渲染圖形的跨平臺(tái)API。
EGL:Embedded Graphics Libarary. EGL是Khronos渲染API(如GLES)與本地窗口系統(tǒng)之間的一個(gè)中間接口層。
texture:OpenGL的對(duì)象,包含一張或多張擁有相同圖片格式的圖片。可以做為Shader(著色器)的來(lái)源,也可以做為渲染目標(biāo)。texture圖片比光滑的圖片多了表面的紋理。
不同設(shè)備的窗口系統(tǒng)千變?nèi)f化,但GLES的API卻是不變的,所以需要EGL協(xié)調(diào)設(shè)備的窗口系統(tǒng)和GLES。
Android用GLES來(lái)渲染圖形,并用EGL來(lái)創(chuàng)建GLES的contexts和為GLES渲染提供繪制的地方。GLES方法用來(lái)渲染textured多邊形,而EGL方法用來(lái)把渲染顯示在屏幕上。
在使用GLES繪制前,你需要?jiǎng)?chuàng)建GL context。在EGL中,這意味著要?jiǎng)?chuàng)建一個(gè)EGLContext和一個(gè)EGLSurface。這個(gè)GL context通過(guò)thread-local storage的方式被GLES訪問(wèn)操作,而不是當(dāng)做一個(gè)參數(shù)被傳遞給GLES訪問(wèn)操作。渲染代碼應(yīng)該在當(dāng)前的GLES線程而不是UI線程執(zhí)行。
EGLSurface(Android)
EGLSurface是操作系統(tǒng)分配的window,它由eglCreateWindowSurface()方法創(chuàng)建。這個(gè)方法不僅創(chuàng)建一個(gè)EGLSurface,還會(huì)把創(chuàng)建的EGLSurface連接到做為輸入?yún)?shù)的Surface的BufferQueue上(做為BufferQueue的生產(chǎn)方),而這個(gè)Surface由BufferQueue的消耗方(SurfaceView、SurfaceTexture、TextureView或者ImageReader等)創(chuàng)建。
這樣,渲染這個(gè)EGLSurface的整個(gè)流程是:從BufferQueue中取出一個(gè)new buffer,渲染這個(gè)buffer,再把被填充的buffer重新插入到BufferQueue中供consumer使用。如下
EGL不提供lock/unlock方法,提供eglSwapBuffers()方法來(lái)提交當(dāng)前繪制的幀。
一個(gè)Surface一次只能和一個(gè)EGLSurface關(guān)聯(lián)(只能有一個(gè)生產(chǎn)方連接到BufferQueue),只有當(dāng)關(guān)聯(lián)的EGLSurface被銷毀后(它將斷開(kāi)與BufferQueue的連接),才允許其它的EGLSurface關(guān)聯(lián)。
一個(gè)線程可以更改它當(dāng)前使用的EGLSurface,但一個(gè)EGLSurface只能同時(shí)被一個(gè)線程使用。
EGL和SurfaceHolder不一樣,它是獨(dú)立與Surface的一個(gè)概念。你可以在一個(gè)并不由Surface支持的EGLSurface上繪圖,你也可以在沒(méi)有EGL的情況下使用Surface。EGLSurface僅僅為GLES提供一個(gè)繪圖的地方。
ANativeWindow
公開(kāi)的Surface類是用Java實(shí)現(xiàn)的,其對(duì)應(yīng)的C/C++類Android NDK中半公開(kāi)的ANativeWindow類。
參考
android develop圖形文檔:https//source.android.com/devices/graphics
原創(chuàng)內(nèi)容歡迎轉(zhuǎn)載,但請(qǐng)注明出處,謝謝!