Android 圖形系統(Graphics)

最近開發遇到問題,ImageView設置visibility未顯示。這時View已經post到主線程顯示,并且父view可以正常顯示。懷疑是系統顯示問題于是對顯示系統進行了學習梳理。

本文將從三個方面介紹Android 圖形系統。

一、圖形系統簡介

1.1 Android 繪制基礎

  1. 系統繪制的是什么?
    圖形緩沖區,也叫Buffer 。應用層的View樹最終會轉換成Buffer,置于BufferQueue中被繪制。
  2. 繪制的位置在哪里?
    應用端會把一切內容渲染到surface上,最終顯示到LCD/OLED顯示屏
  3. 如何把圖像繪制到屏幕?

    繪制任務由應用發起,通過跨進程方式把Buffer傳到FW層,由FW層中的SurfaceFlinger服務調用Linux 硬件驅動最終繪制到硬件屏幕上。

1.2 Android 圖形引擎

圖形系統提供繪圖和圖形處理支持。
Android 框架提供了各種用于 2D 和 3D 圖形渲染的 API、圖片解碼庫,以及各種Driver支持。
? 繪圖API:2D引擎 Skia,3D引擎 OpenGL ES,RenderScript,OpenCV和Vulkan。
? 圖片解碼庫:jpg,png,gif等。


應用開發者可通過三種方式將圖像繪制到屏幕:
? Canvas : 2D圖形API,Android View樹實際的繪制者。
? OpenGL ES : 嵌入式設備的OpenGL 三維圖形API子集。
? Vulkan :跨平臺的2D和3D繪圖引擎,Android 7.0后支持,NDK。

1.3 圖形系統架構

整個圖形系統架構是一個生產者和消費者模式,五層依次介紹:

  1. Image Stream Producers :
    ? view每次執行lockCanvas->draw->unlockCanvas,會存入一幀數據進入BufferQueue中
  2. Native Framework:
    ? Buffer的生成和BufferQueue數據跨進程傳遞
  3. WindowManager:
    ? 計算窗口大小,位置等,同時也會將相應的參數設置給SurfaceFlinger,比如Window的z-order和大小等。
  4. Image stream consumers :
    ? SurfaceFlinger,消耗當前可見的 Surface,作為Layer的管理著,同是也是BufferQueue的消費者,當每個Layer的生產者繪制完一幀時,會通知SurfaceFlinger。
  5. HAL:
    ? Gralloc: 圖形內存分配器,分配圖像生產方請求的內存
    ? Hardware Composer:硬件混合渲染器,合成SurfaceFlinger里面的Layer,并顯示

二、圖形組件與繪制流程

2.1 2D/3D繪圖流程

2D rendering path

2D繪制:Canvas api / view 的子類 (button ,list)/自定義view


3D rendering path

3D繪制:應用直接使用OpenGL 接口繪制圖形(PixelFlinger對應的是openGl 1.0 ,GUP driver 對應的是2.0和3.0)

所有情況下的繪圖都渲染到一個包含 GraphicBuffer的Surface上,當一塊 Surface 顯示在屏幕上時,就是用戶所看到的窗口。

2.2 Canvas/ Skia/ hwui/ OpenGL ES

? Canvas:畫布,2D圖形API,Android View樹實際的渲染者。
? Skia繪制:Android4.0之前默認使用,主線程通過CPU完成繪圖指令操作,在復雜場景下單幀容易超過16ms導致卡頓。

? hwui硬件加速繪制:使用GUP繪制, Android4.0及以后默認開啟硬件加速渲染。5.0以后把渲染拆分成了兩個線程:主線程負責記錄渲染指令,渲染線程負責通過OpenGL ES完成渲染,兩個線程并發執行。

注意:并非所有 2D 繪制操作都支持硬件加速,可能會影響部分自定義視圖或繪制調用。詳情見:Android硬件加速
? OpenGL ES : OpenGL 三維圖形 API 的子集,針對手機、PDA和游戲主機等嵌入式設備而設計。在異步線程直接通過OpenGL ES進行渲染,一般適用于游戲、視頻播放等獨立場景

2.3 圖形組件WMS

WindowManagerService(WMS)窗口管理服務,管理系統中所有的窗口。
? 管理window (view的容器)
? Window與surface對應,一塊顯示區域。添加一個window,就是 WMS 為其分配一塊 Surface 的過程。

? WindowManager為 SurfaceFlinger 提供窗口元數據(window metadata)

Android setContentView就是將View設置到widow上。

WMS角色在整個流程的位置:

這里有一個wm命令可以看到window的信息:對手機分辨率、像素密度、顯示區域進行設置的命令

2.4 Surface與相關的view

Google 在Android source官網提示:

“ What every developer should know about surfaces, SurfaceHolder, EGLSurface, SurfaceView, GLSurfaceView, SurfaceTexture, TextureView, SurfaceFlinger, and Vulkan.”

這里就對這些控件進行簡單介紹:

Surface

Surface : Handle onto a raw buffer that is being managed by the screen compositor.
Surface 對應一塊屏幕緩沖區。生產者是: SurfaceTexture、MediaRecorder 等,消費者是: OpenGL、MediaPlayer 或 CameraDevice等。每個window對應一個Surface。Canvas或OpenGL ES等最終都渲染到Surface上。
? Flutter在Android平臺上也是直接渲染到Surface。例如:一個Activity/Dialog都是一個Surface,它承載了上層的圖形數據,與SurfaceFlinger側的Layer相對應。

屏幕上的每一幀圖像都是多個surface合成后的結果:
Canvas rendering:

Canvas(畫布)實現由 Skia 圖形庫提供。為了確保兩個客戶端不會同時更新某個緩沖區,使用以下命令處理畫布鎖:


SurfaceView和SurfaceHolder
SurfaceView

使用雙緩沖機制,有自己的 surface,View只是一個透明的占位符,Surface可以在后臺線程中繪制。雙緩沖機制提高渲染效率,獨立線程
繪制,提升流暢性。適合一些場景:需要界面迅速更新、UI繪制時間長、對幀率要求較高的情況。

SurfaceHolder

提供訪問和控制Surface 相關的方法 。通過SurfaceView的getHolder()函數可以獲取SurfaceHolder對象,Surface 就在SurfaceHolder對象內。
addCallback(SurfaceHolder.Callbackcallback) /Canvas lockCanvas() /unlockCanvasAndPost(Canvascanvas)

SurfaceTexture/ GLSurfaceView/ TextureView

SurfaceTexture: Surface 和 OpenGL ES (GLES) 紋理(Texture)的組合。將圖像流轉為 OpenGL 外部紋理。
TextureView:持有 SurfaceTexture,將圖像處理為 OpenGL 紋理更新到 HardwareLayer。
GLSurfaceView:加入 EGL 管理,自帶 GL 上下文和 GL 渲染線程
這些View通常涉及到Android音視頻相關,需要高效的渲染能力。如下面的SurfaceTexture在camera中的應用。


GraphicBuffer / BufferQueue

GraphicBuffer

簡稱Buffer, 一個Buffer包含一幀圖像,Buffer由gralloc分配和回收。Buffer 屬性包含:width, height, format, usage等

BufferQueue

BufferQueue 的引入是為了解決顯示和性能問題。
? Surface屬于APP進程,Layer屬于系統進程,如果它們之間只用一個Buffer,會存在顯示和性能問題。
? 一些Buffer用于繪制,一些Buffer用于顯示,雙方處理完之后,交換一下Buffer,提高效率。
? BufferQueue中包含多個Buffer對象。


Android圖形系統包含了兩對生產者和消費者模型,它們都通過BufferQueue進行連接:
1.Canvas和OpenGL ES生產圖形數據,SurfaceFlinger消費圖形數據。
2.SurfaceFlinger合成所有圖層的圖形數據,Display顯示合成結果。

SurfaceFlinger

code:frameworks/native/services/surfaceflinger
? Surface表示APP進程的一個窗口,承載了窗口的圖形數據。
? SurfaceFlinger是系統進程合成所有窗口的系統服務,負責合成所有Surface提供的圖形數據,然后送顯到屏幕。
? SurfaceFlinger既是上層應用的消費者,又是Display的生產者,起到了承上啟下的作用。
數據流:



合成示意圖:



SurfaceFlinger的啟動流程:
Surface Flinger 服務由init進程啟動,一個高優先級的本地守護進程。SurfaceFlinger啟動流程

Android系統的啟動流程:

可以看到SurfaceFlinger的啟動是和Zygote進程啟動位于同一流程中。

SurfaceFlinger API

Vsync機制

在介紹Vsync機制之前先介紹兩個重要概念:

屏幕刷新率:屏幕每秒鐘可以刷新多少次。60HZ刷新率,16.7ms刷新一次。(120HZ/8.3ms),硬件指標。
GPU 繪制幀率:GPU 每秒能夠合成繪制多少幀。

軟件層觸發 View 繪制的時機是隨機的,當下一次屏幕刷新時,屏幕從 Frame Buffer 中拿到的數據還是“幀1”的數據,導致“丟幀”。


每隔 16ms 硬件層發出 vsync 信號,應用層接收到此信號后會觸發UI 的渲染流程,同時 vsync 信號也會觸發 SurfaceFlinger 讀取Buffer 中的數據,進行合成顯示到屏幕上。



總結:Vsync機制將 CPU 和 GPU 的開始時間與屏幕刷新強行拖拽到同一起跑線

三、Graphics問題總結

Android提供的Graphics流程相對比較復雜對其進行具象后的流程如下兩張圖所示:



?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容