當前位置:
首頁 > 最新 > HenCoder Android 自定義 View 1-8 硬體加速

HenCoder Android 自定義 View 1-8 硬體加速

硬體加速這個詞每當被提及,很多人都會感興趣。這個詞給大部分人的概念大致有兩個:快速、不穩定。對很多人來說,硬體加速似乎是一個只可遠觀而不可褻玩的高端科技:是,我聽說它很牛逼,但我不敢「亂」用,因為我怕 hold 不住。

今天我試著就把硬體加速的外衣脫掉(並沒有),聊一聊它的原理和應用:

硬體加速的本質和原理;

硬體加速在 Android 中的應用;

硬體加速在 Android 中的限制。

本篇是 「HenCoder Android 開發進階」自定義 View 部分的最後一篇:硬體加速。

如果你沒聽說過 HenCoder,也可以看看這個:

HenCoder:給高級 Android 工程師的進階手冊

概念

在正式開始之前需要說明一下,作為繪製部分的最後一期,本期內容只是為了內容的完整性做一個補充,因為之前好幾期的內容里都有涉及硬體加速的技術點,而一些讀者因為不了解硬體加速而產生了一些疑問。所以僅僅從難度上來講,這期的內容並不難,並且本期的大部分內容你都可以從這兩個頁面中找到:

https://developer.android.google.cn/guide/topics/graphics/hardware-accel.html

https://www.youtube.com/watch?v=v9S5EO7CLjo

下面進入正題。

所謂硬體加速,指的是把某些計算工作交給專門的硬體來做,而不是和普通的計算工作一樣交給 CPU 來處理。這樣不僅減輕了 CPU 的壓力,而且由於有了「專人」的處理,這份計算工作的速度也被加快了。這就是「硬體加速」。

而對於 Android 來說,硬體加速有它專屬的意思:在 Android 里,硬體加速專指把 View 中繪製的計算工作交給 GPU 來處理。進一步地再明確一下,這個「繪製的計算工作」指的就是把繪製方法中的那些變成實際的像素這件事。

原理

在硬體加速關閉的時候,繪製的工作方式是:把要繪製的內容寫進一個,然後在之後的渲染過程中,這個的像素內容被直接用於渲染到屏幕。這種繪製方式的主要計算工作在於把繪製操作轉換為像素的過程(例如由一句來獲得一個具體的圓的像素信息),這個過程的計算是由 CPU 來完成的。大致就像這樣:

而在硬體加速開啟式,的工作方式改變了:它只是把繪製的內容轉換為 GPU 的操作保存了下來,然後就把它交給 GPU,最終由 GPU 來完成實際的顯示工作。大致是這樣:

如圖,在硬體加速開啟時,CPU 做的事只是把繪製工作轉換成 GPU 的操作,這個工作量相對來說是非常小的。

怎麼就「加速」了?

從上面的圖中可以看出,硬體加速開啟後,繪製的計算工作由 CPU 轉交給了 GPU。不過這怎麼就能起到「加速」作用,讓繪製變快了呢?

硬體加速能夠讓繪製變快,主要有三個原因:

本來由 CPU 自己來做的事,分攤給了 GPU 一部分,自然可以提高效率;

相對於 CPU 來說,GPU 自身的設計本來就對於很多常見類型內容的計算(例如簡單的圓形、簡單的方形)具有優勢;

由於繪製流程的不同,硬體加速在界面內容發生重繪的時候繪製流程可以得到優化,避免了一些重複操作,從而大幅提升繪製效率。

其中前兩點可以總結為一句:用了 GPU,繪製就是快。原因很直觀,不再多說。

關於第三點,它的原理我大致說一下:

前面說到,在硬體加速關閉時,繪製內容會被 CPU 轉換成實際的像素,然後直接渲染到屏幕。具體來說,這個「實際的像素」,它是由來承載的。在界面中的某個 View 由於內容發生改變而調用方法時,如果沒有開啟硬體加速,那麼為了正確計算的像素,這個的父 View、父 View 的父 View 乃至一直向上直到最頂級 View,以及所有和它相交的兄弟,都需要被調用來重繪。一個 View 的改變使得大半個界面甚至整個界面都重繪一遍,這個工作量是非常大的。

而在硬體加速開啟時,前面說過,繪製的內容會被轉換成 GPU 的操作保存下來(承載的形式稱為 display list,對應的類也叫做),再轉交給 GPU。由於所有的繪製內容都沒有變成最終的像素,所以它們之間是相互獨立的,那麼在界面內容發生改變的時候,只要把發生了改變的 View 調用方法以更新它所對應的 GPU 操作就好,至於它的父 View 和兄弟 View,只需要保持原樣。那麼這個工作量就很小了。

正是由於上面的原因,硬體加速不僅是由於 GPU 的引入而提高了繪製效率,還由於繪製機制的改變,而極大地提高了界面內容改變時的刷新效率。

所以把上面的三條壓縮總結一下,硬體加速更快的原因有兩條:

用了 GPU,繪製變快了;

繪製機制的改變,導致界面內容改變時的刷新效率極大提高。

限制

如果僅僅是這樣,硬體加速只有好處沒有缺陷,那大家都不必關心硬體加速了,這篇文章也不會出現:既然是好東西就用唄,關心那麼多原理幹嗎?

可事實就是,硬體加速不只是好處,也有它的限制:收到 GPU 繪製方式的限制,的有些方法在硬體加速開啟式會失效或無法正常工作。比如,在硬體加速開啟時,在 API 18 及以上的系統中才有效。具體的 API 限制和 API 版本的關係如下圖:

所以,如果你的自定義控制項中有自定義繪製的內容,最好參照一下這份表格,確保你的繪製操作可以正確地在所有用戶的手機里能夠正常顯示,而不是只在你的運行了最新版本 Android 系統的 Nexus 或 Pixel 里測試一遍沒問題就發布了。小心被祭天。

不過有一點可以放心的是,所有的原生自帶控制項,都沒有用到 API 版本不兼容的繪製操作,可以放心使用。所以你只要檢查你寫的自定義繪製就好。

View Layer

在之前幾期的內容里我提到過幾次,如果你的繪製操作不支持硬體加速,你需要手動關閉硬體加速來繪製界面,關閉的方式是通過這行代碼:

有不少人都有過疑問:什麼是 layer type?如果這個方法是硬體加速的開關,那麼它的參數為什麼不是一個來關閉硬體加速以及一個來打開硬體加速這麼兩個參數,而是三個參數,在和之外還有一個?難道還能既不用軟體繪製,也不用硬體繪製嗎?

事實上,這個方法的本來作用並不是用來開關硬體加速的,只是當它的參數為的時候,可以「順便」把硬體加速關掉而已;並且除了這個方法之外,Android 並沒有提供專門的 View 級別的硬體加速開關,所以它就「順便」成了一個開關硬體加速的方法。

這個方法,它的作用其實就是名字里的意思:設置 View Layer 的類型。所謂 View Layer,又稱為離屏緩衝(Off-screen Buffer),它的作用是單獨啟用一塊地方來繪製這個 View ,而不是使用軟體繪製的 Bitmap 或者通過硬體加速的 GPU。這塊「地方」可能是一塊單獨的,也可能是一塊 OpenGL 的紋理(texture,OpenGL 的紋理可以簡單理解為圖像的意思),具體取決於硬體加速是否開啟。採用什麼來繪製 View 不是關鍵,關鍵在於當設置了 View Layer 的時候,它的繪製會被緩存下來,而且緩存的是最終的繪製結果,而不是像硬體加速那樣只是把 GPU 的操作保存下來再交給 GPU 去計算。通過這樣更進一步的緩存方式,View 的重繪效率進一步提高了:只要繪製的內容沒有變,那麼不論是 CPU 繪製還是 GPU 繪製,它們都不用重新計算,而只要只用之前緩存的繪製結果就可以了。

多說一句,其實這個離屏緩衝(Off-screen Buffer),更準確的說應該叫做離屏緩存(Off-screen Cache)會更合適一點。原因在上面這一段里已經說過了,因為它其實是緩存而不是緩衝。(這段話僅代表個人意見)

基於這樣的原理,在進行移動、旋轉等(無需調用)的屬性動畫的時候開啟 Hardware Layer 將會極大地提升動畫的效率,因為在動畫過程中 View 本身並沒有發生改變,只是它的位置或角度改變了,而這種改變是可以由 GPU 通過簡單計算就完成的,並不需要重繪整個 View。所以在這種動畫的過程中開啟 Hardware Layer,可以讓本來就依靠硬體加速而變流暢了的動畫變得更加流暢。實現方式大概是這樣:

或者如果是使用,那麼更簡單:

不過一定要注意,只有你在對等無需調用的屬性做動畫的時候,這種方法才適用,因為這種方法本身利用的就是當界面不發生時,緩存未更新所帶來的時間的節省。所以簡單地說——

這種方式不適用於基於自定義屬性繪製的動畫。一定記得這句話。

另外,除了用於關閉硬體加速和輔助屬性動畫這兩項功能外,Layer 還可以用於給 View 增加一些繪製效果,例如設置一個來讓 View 變成黑白的:

另外,由於設置了 View Layer 後,View 在初次繪製時以及每次後重繪時,需要進行兩次的繪製工作(一次繪製到 Layer,一次從 Layer 繪製到顯示屏),所以其實它的每次繪製的效率是被降低了的。所以一定要慎重使用 View Layer,在需要用到它的時候再去使用。

總結

本期內容就到這裡,就像開頭處我說的,本期只是作為一個完整性的補充,並沒有太多重要或高難度的東西,我也沒有準備視頻或太多的截圖或動圖來做說明。慣例總結一下:

硬體加速指的是使用 GPU 來完成繪製的計算工作,代替 CPU。它從工作分攤和繪製機制優化這兩個角度提升了繪製的速度。

硬體加速可以使用來關閉硬體加速,但這個方法其實是用來設置 View Layer 的:

參數為時,使用軟體來繪製 View Layer,繪製到一個 Bitmap,並順便關閉硬體加速;

參數為時,使用 GPU 來繪製 View Layer,繪製到一個 OpenGL texture(如果硬體加速關閉,那麼行為和一致);

參數為時,關閉 View Layer。

View Layer 可以加速無時的刷新效率,但對於需要調用的刷新無法加速。

View Layer 繪製所消耗的實際時間是比不使用 View Layer 時要高的,所以要慎重使用。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 公眾號 的精彩文章:

神腦洞!這家三板企業首推「共享女友」 押金8000一天298你要嗎?
征服中國,田中義一86年前給日本天皇的秘密奏摺
今天教你織圍巾,秋冬就要到了,你想送給誰?
PPT科研作圖②——圖片預處理
試論玄空飛星斷吉凶九大要點

TAG:公眾號 |