關(guān)于 Android 渲染你應該了解的知識點

前言

談到AndroidUI繪制童社,大家可能會想到onMeasureonLayout斗埂、onDraw三大流程符糊。但我們的View到底是如何一步一步顯示到屏幕上的?onDraw之后到View顯示到屏幕上呛凶,具體又做了哪些工作? 帶著這些問題男娄,我們今天就深入學習一下Android渲染的流程吧,本文主包括以下內(nèi)容:

  1. Android渲染的整體架構(gòu)是怎樣的?

  2. Android渲染的生產(chǎn)者包括哪些漾稀?SkiaOpenGl的區(qū)別是什么模闲?

  3. 什么是硬件加速?硬件繪制與軟件繪制的區(qū)別

  4. Android渲染緩沖區(qū)是什么崭捍?什么是黃油計劃?

  5. Android渲染的消費者是什么? 什么是SurfaceFlinger?

Android渲染整體架構(gòu)

image
我們先來看一下Android渲染的整體架構(gòu)尸折,具體可分為以下幾個部分

  • image stream produceers: 渲染數(shù)據(jù)的生產(chǎn)者,如Appdraw方法會把繪制指令通過canvas傳遞給framework層的RenderThread線程殷蛇。

  • native Framework: RenderThread線程通過surface.dequeue得到緩沖區(qū)graphic bufer实夹,然后在上面通過OpenGL來完成真正的渲染命令。在把緩沖區(qū)交還給BufferQueue隊列中粒梦。

  • image stream consumers: surfaceFlinger從隊列中獲取數(shù)據(jù)亮航,同時和HAL完成layer的合成工作,最終交給HAL展示匀们。

  • HAL: 硬件抽象層缴淋。把圖形數(shù)據(jù)展示到設(shè)備屏幕

可以看出,這其實是個很典型的生產(chǎn)者消費者模式
image
  • 圖像生產(chǎn)者: 也就是我們的APP泄朴,再深入點就是canvas->surface重抖。

  • 圖像消費者:SurfaceFlinger

  • 圖像緩沖區(qū):BufferQueue,一般是3緩沖區(qū)

下面我們就從生產(chǎn)者祖灰,消費者钟沛,緩沖區(qū)三個部分來詳細了解下Android渲染的過程

圖像生產(chǎn)者

從上面的架構(gòu)圖可知,圖像的生產(chǎn)者主要有MediaPlayer局扶,CameraPreview恨统,NDK(Skia)OpenGl ES详民。 其中MediaPlayerCamera Preview是通過直接讀取圖像源來生成圖像數(shù)據(jù)延欠,NDK(Skia)陌兑,OpenGL ES是通過自身的繪制能力生產(chǎn)的圖像數(shù)據(jù)

OpenGL沈跨、VulkanSkia的區(qū)別

  • OpenGL: 是一種跨平臺的3D圖形繪制規(guī)范接口兔综。OpenGL EL則是專門針對嵌入式設(shè)備饿凛,如手機做了優(yōu)化狞玛。

  • Skiaskia是圖像渲染庫,2D圖形繪制自己就能完成涧窒。3D效果(依賴硬件)由OpenGL心肪、VulkanMetal支持纠吴。它不僅支持2D硬鞍、3D,同時支持CPU軟件繪制和GPU硬件加速戴已。Android固该、flutter都是使用它來完成繪制。

  • Vulkan: Android引入了Vulkan支持糖儡。VulKan是用來替換OpenGL的伐坏。它不僅支持3D,也支持2D握联,同時更加輕量級

硬件加速

關(guān)于硬件加速桦沉,相信大家也經(jīng)常聽到,尤其是有些API不支持硬件加速金闽,因此需要我們手動關(guān)閉纯露,那么硬件加速到底是什么呢?

CPUGPU的區(qū)別

除了屏幕,UI 渲染還要依賴另外兩個核心的硬件:CPUGPU呐矾。

  • CPUCentral Processing Unit苔埋,中央處理器),是計算機系統(tǒng)的運算和控制核心蜒犯,是信息處理组橄、程序運行的最終執(zhí)行單元;

  • GPUGraphics Processin Unit罚随,圖形處理器)玉工,是一種專門用于圖像運算的處理器,在計算機系統(tǒng)中通常被稱為 "顯卡"的核心部件就是 GPU淘菩。

UI 組件在繪制到屏幕之前遵班,都需要經(jīng)過 Rasterization(柵格化)操作,而柵格化又是一個非常耗時的操作潮改。 [圖片上傳失敗...(image-1273b8-1675927727899)] Rasterization 柵格化是繪制那些 Button狭郑、ShapePath汇在、String翰萨、Bitmap 等顯示組件最基礎(chǔ)的操作。柵格化將這些 UI 組件拆分到顯示器的不同像素上進行顯示糕殉。這是一個非常耗時的操作亩鬼,GPU 的引入就是為了加快柵格化殖告。

硬件繪制與軟件繪制

  • ,軟件繪制使用 Skia 庫雳锋,它是一款能在低端設(shè)備黄绩,如手機呈現(xiàn)高質(zhì)量的 2D 跨平臺圖形框架,類似 Chrome玷过、Flutter 內(nèi)部使用的都是 Skia 庫爽丹。

  • 硬件繪制的思想就是通過底層軟件代碼,將 CPU 不擅長的圖形計算轉(zhuǎn)換成 GPU 專用指令辛蚊,由 GPU 完成繪制任務习劫。

所以說硬件加速的本質(zhì)就是使用GPU代替CPU完成Graphic Buffer繪制工作,以實現(xiàn)更好的性能嚼隘,Android從4.0開始默認開啟了硬件加速诽里,但還有一些API不支持硬件加速,因此需要手動關(guān)閉硬件加速飞蛹。 需要注意的是谤狡,軟件繪制使用的Skia庫,但這不代表Skia不支持硬件加速卧檐,從Android 8開始墓懂,我們可以選擇使用Skia進行硬件加速,Android 9開始就默認使用Skia來進行硬件加速霉囚。Skia的硬件加速主要是通過 copybit 模塊調(diào)用OpenGL或者SKia來實現(xiàn)捕仔。

圖像緩沖區(qū)

Android中的圖像生產(chǎn)者OpenGLSkia盈罐,Vulkan將繪制的數(shù)據(jù)存放在圖像緩沖區(qū)中榜跌,Android中的圖像消費SurfaceFlinger從圖像緩沖區(qū)將數(shù)據(jù)取出,進行加工及合成 那么圖像緩沖區(qū)我們又需要注意哪些內(nèi)容呢?

黃油計劃

優(yōu)化是無止境的盅粪,Google 在 2012 年的 I/O 大會上宣布了 Project Butter 黃油計劃钓葫,并且在 Android 4.1 中正式開啟了這個機制。

VSYNC信號

VSYNC(Vertical Synchronization)是理解 Project Butter 的核心票顾。對于 Android 4.0础浮,CPU 可能會因為在忙其他的事情,導致沒來得及處理 UI 繪制奠骄。 為了解決這個問題豆同,系統(tǒng)在收到VSync信號后,將馬上開始下一幀的渲染含鳞。即一旦收到VSync通知(16ms觸發(fā)一次)影锈,CPUGPU 才立刻開始計算然后把數(shù)據(jù)寫入buffer。如下圖 [圖片上傳失敗...(image-eb415-1675927727899)]

CPU/GPU根據(jù)VSYNC信號同步處理數(shù)據(jù),可以讓CPU/GPU有完整的16ms時間來處理數(shù)據(jù),減少了jank。 一句話總結(jié)嘿般,VSync同步使得CPU/GPU充分利用了16.6ms時間魂仍,減少jank

三緩沖機制

Android 4.0之前磁滚,Android采用雙緩沖機制佛吓,讓繪制和顯示器擁有各自的bufferGPU 始終將完成的一幀圖像數(shù)據(jù)寫入到 Back Buffer,而顯示器使用 Frame Buffer垂攘,當屏幕刷新時维雇,Frame Buffer 并不會發(fā)生變化,當Back buffer準備就緒后晒他,它們才進行交換吱型。

但是如果界面比較復雜,CPU/GPU的處理時間較長 超過了16.6ms呢陨仅,雙緩沖機制會帶來什么問題津滞?如下圖: [圖片上傳失敗...(image-75841b-1675927727899)]

  • 在第二個時間段內(nèi),但卻因 GPU 還在處理 B 幀灼伤,緩存沒能交換触徐,導致 A 幀被重復顯示。

  • B完成后狐赡,又因為缺乏VSync信號撞鹉,它只能等待下一個signal的來臨。于是在這一過程中颖侄,有一大段時間是被浪費的鸟雏。

  • 當下一個VSync出現(xiàn)時,CPU/GPU馬上執(zhí)行操作(A幀)览祖,且緩存交換崔慧,相應的顯示屏對應的就是B。這時看起來就是正常的穴墅。只不過由于執(zhí)行時間仍然超過16ms惶室,導致下一次應該執(zhí)行的緩沖區(qū)交換又被推遲了——如此循環(huán)反復,便出現(xiàn)了越來越多的“Jank”玄货。

三緩沖就是在雙緩沖機制基礎(chǔ)上增加了一個Graphic Buffer緩沖區(qū)皇钞,這樣可以最大限度的利用空閑時間,帶來的壞處是多使用的一個Graphic Buffer所占用的內(nèi)存松捉。 [圖片上傳失敗...(image-8c8ef2-1675927727899)] 三緩沖機制有效利用了等待vysnc的時間夹界,可以幫助我們減少了jank

RenderThread

經(jīng)過 Android 4.1Project Butter 黃油計劃之后,Android 的渲染性能有了很大的改善隘世。不過你有沒有注意到這樣一個問題可柿,雖然利用了 GPU 的圖形高性能運算鸠踪,但是從計算 DisplayList,到通過 GPU 繪制到 Frame Buffer复斥,整個計算和繪制都在 UI 主線程中完成营密。

UI 線程任務過于繁重。如果整個渲染過程比較耗時目锭,可能造成無法響應用戶的操作评汰,進而出現(xiàn)卡頓的情況。GPU 對圖形的繪制渲染能力更勝一籌痢虹,如果使用 GPU 并在不同線程繪制渲染圖形被去,那么整個流程會更加順暢。

正因如此奖唯,在 Android 5.0 引入兩個比較大的改變惨缆。一個是引入了 RenderNode 的概念,它對 DisplayList 及一些 View 顯示屬性都做了進一步封裝丰捷。另一個是引入了 RenderThread踪央,所有的 GL 命令執(zhí)行都放到這個線程上,渲染線程在 RenderNode 中存有渲染幀的所有信息瓢阴,可以做一些屬性動畫畅蹂,這樣即便主線程有耗時操作的時候也可以保證動畫流程。

圖像消費者

SurfaceFlingerAndroid系統(tǒng)中最重要的一個圖像消費者荣恐,Activity繪制的界面圖像液斜,都會傳遞到SurfaceFlinger來,SurfaceFlinger的作用主要是接收GraphicBuffer叠穆,然后交給HWComposer或者OpenGL做合成少漆,合成完成后,SurfaceFlinger會把最終的數(shù)據(jù)提交給FrameBuffer硼被。

SurfaceFlinger是圖像數(shù)據(jù)的消費者示损。在應用程序請求創(chuàng)建surface的時候,SurfaceFlinger會創(chuàng)建一個Layer嚷硫。LayerSurfaceFlinger操作合成的基本單元检访。所以,一個surface對應一個Layer仔掸。 當應用程序把繪制好的GraphicBuffer數(shù)據(jù)放入BufferQueue后脆贵,接下來的工作就是SurfaceFlinger來完成了。

image

系統(tǒng)會有多個應用程序起暮,一個程序有多個BufferQueue隊列卖氨。SurfaceFlinger就是用來決定何時以及怎么去管理和顯示這些隊列的。 SurfaceFlinger請求HAL硬件層,來決定這些Buffer是硬件來合成還是自己通過OpenGL來合成筒捺。 最終把合成后的buffer數(shù)據(jù)柏腻,展示在屏幕上。

總結(jié)

總得來說系吭,Android圖像渲染機制是一個生產(chǎn)者消費者的模型五嫂,如下圖所示:

image

  • onMeasureonLayout計算出view的大小和擺放的位置村斟,這都是UI線程要做的事情,在draw方法中進行繪制抛猫,但此時是沒有真正去繪制蟆盹。而是把繪制的指令封裝為displayList,進一步封裝為RenderNode,在同步給RenderThread闺金。

  • RenderThread通過dequeue拿到graphic buffersurfaceFlinger的緩沖區(qū))逾滥,根據(jù)繪制指令直接操作OpenGL的繪制接口,最終通過GPU設(shè)備把繪制指令渲染到了離屏緩沖區(qū)graphic buffer败匹。

  • 完成渲染后寨昙,把緩沖區(qū)交還給SurfaceFlingerBufferQueueSurfaceFlinger會通過硬件設(shè)備進行layer的合成掀亩,最終展示到屏幕舔哪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市槽棍,隨后出現(xiàn)的幾起案子捉蚤,更是在濱河造成了極大的恐慌,老刑警劉巖炼七,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缆巧,死亡現(xiàn)場離奇詭異,居然都是意外死亡豌拙,警方通過查閱死者的電腦和手機陕悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來按傅,“玉大人捉超,你說我怎么就攤上這事∥ㄉ埽” “怎么了狂秦?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長推捐。 經(jīng)常有香客問我裂问,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任堪簿,我火速辦了婚禮痊乾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椭更。我一直安慰自己哪审,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布虑瀑。 她就那樣靜靜地躺著湿滓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舌狗。 梳的紋絲不亂的頭發(fā)上叽奥,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音痛侍,去河邊找鬼朝氓。 笑死,一個胖子當著我的面吹牛主届,可吹牛的內(nèi)容都是我干的赵哲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼君丁,長吁一口氣:“原來是場噩夢啊……” “哼枫夺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起绘闷,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤筷屡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后簸喂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毙死,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年喻鳄,在試婚紗的時候發(fā)現(xiàn)自己被綠了扼倘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡除呵,死狀恐怖再菊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颜曾,我是刑警寧澤纠拔,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站泛豪,受9級特大地震影響稠诲,放射性物質(zhì)發(fā)生泄漏侦鹏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一臀叙、第九天 我趴在偏房一處隱蔽的房頂上張望略水。 院中可真熱鬧,春花似錦劝萤、人聲如沸渊涝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跨释。三九已至,卻和暖如春厌处,著一層夾襖步出監(jiān)牢的瞬間鳖谈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工嘱蛋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蚯姆,地道東北人五续。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓洒敏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疙驾。 傳聞我的和親對象是個殘疾皇子凶伙,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容