翻出了4年前實習(xí)期間手繪梳理的Android圖形框架,其實有些細節(jié)都記不清了。 所以這里再文字梳理一邊,加深理解也作為一個積淀,接下來希望能梳理清楚Android系統(tǒng)如何進行HDR上屏的。
先籠統(tǒng)來說,我們知道,我們將某個圖像在Androids設(shè)備上顯示涉及下述環(huán)節(jié):
1. 我們將要顯示的數(shù)據(jù)交付給Android系統(tǒng)(Canvas、OpenGLES、Vulkan),
2. Android系統(tǒng)將要顯示的內(nèi)容處理成相應(yīng)的buffer(GUI+芯片),
3. 顯示硬件根據(jù)buffer數(shù)據(jù)使顯示屏每個像素發(fā)出對應(yīng)的光(LCD、OLED屏幕設(shè)備)。
GUI架構(gòu)處理的就是上述的第二步。
———— ———— ———————————————————————————
推薦相關(guān)文章:
從Android的基本View組件解釋view hierarchy如何與Android GUI協(xié)作:
https://www.zhihu.com/question/25811504
GUI最重要成員Surface、SurfaceFlinger介紹:
Android 卷I-Surface系統(tǒng),從Android的基本View組件解釋view hierarchy如何與Android GUI協(xié)作:
https://wiki.jikexueyuan.com/project/deep-android-v1/surface.html
SurfaceFlinger 圖形系統(tǒng):
https://blog.csdn.net/freekiteyu/article/details/79483406
SurfaceFlinger 用于應(yīng)用程序的典型繪圖流程:
https://blog.csdn.net/xuesen_lin/article/details/8954840
SurfaceFlinger如何OpenGLES聯(lián)動起來:
https://blog.csdn.net/xuesen_lin/article/details/8954553
承載圖像信息的Buffer的介紹:
羅神的Android幀緩沖區(qū)(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現(xiàn)原理分析: https://blog.csdn.net/Luoshengyang/article/details/7747932
———— ———— ———————————————————————————
從手繪紙最上面開始說吧,Android 框架提供了各種用于 2D 和 3D 圖形渲染的 API,可與制造商的圖形驅(qū)動程序?qū)崿F(xiàn)代碼交互,
應(yīng)用開發(fā)者可通過三種方式將圖像繪制到屏幕上:使用畫布、OpenGL ES 或 Vulkan。2D指的沒有開啟硬件加速的Canvas,但是針對Android 4.0以上的系統(tǒng),默認開啟了硬件加速,所以我們基本上可以理解圖像繪制目前市面上Android手機都會用到GPU處理。
不過不管是2D還是3D、Canvas還是gles或是Vulkan,我們都會把繪制數(shù)據(jù)畫到Surface上去。注意這里Surface不等于我們常說SurfaceView。最直接理解,Surface就是作為SurfaceFlinger的代理,SurfaceFlinger作為系統(tǒng)服務(wù),是系統(tǒng)資源,供各個App使用,每個App要去用這個資源就需要代理交接,而這個代理對接什么呢?window,窗口。
Window擁有一個Surface,在Surface里繪制Window里的內(nèi)容。一個application通過ViewRoot向Windows Manager Service申請創(chuàng)建窗口,WMS也是系統(tǒng)服務(wù)負責(zé)分配窗口資源,Windows Manager為每一個窗口創(chuàng)建Surface來讓application在上面繪制各種物體。我們看到android機上各種圖案都是通過一個個win來組織的,win有很多種 比如systemWindow,status bar(電量、wifi、信號那塊)、navigation bar(home頁,前進,后退)、還有我們開發(fā)者最熟悉的Activity對應(yīng)的win,application window。各種window,z軸疊加,如果布局不好會擋住,這也是為什么各種劉海屏幕、曲面屏幕,手機廠商都有一定的適配工作。
Activity內(nèi)的各種子view布局就靈活很多,最終布局也會由ViewRoot來管理,管理的結(jié)構(gòu)是一個叫View Hierarchy(視窗繼承關(guān)系)根據(jù)這個關(guān)系,View Root把Activity里的各種子View 布局好規(guī)劃好映射到 Surface里的buffer里去,這樣子,當我們一個View內(nèi)容發(fā)生改變的時候,我們不用整個surface里面的buffer更新,只用更新部分區(qū)域,這個過程就是下圖中的invalidate和draw。
說到這里,可以引出 SurfaceView,它獨立于Activity,有自己的線程(當然 生命周期還是需要依附于Activity),有自己獨立的window,我們知道window是z軸排列的,所以一般SurfaceView是與Activity是存在“覆蓋”關(guān)系的,在有的比較低性能的手機上我們切換應(yīng)用的時候,可以看到activity與surfaceview是分開的,activity的一般會布局上“挖個透明區(qū)域”留給SurfaceView顯示。由于SurfaceView的獨立線程特性,使得它很適合用來做一些相對耗時可能會block的事情,比如視頻媒體相關(guān)的。
同時媒體展示還有一個常用的控件,叫做TextureView,參考到Google Android Developer:https://developer.android.com/reference/android/view/TextureView,這個控件通過SurfaceTexture可以使用GPU資源,這點跟SurfaceView一樣,但是它沒有自己獨立的window,它跟其他控件一樣從屬于ViewRoot,對應(yīng)的是整個Activity的window,在View Hierarchy結(jié)構(gòu)中,也是為什么這個控件可以輕易的“ moved, transformed, animated, etc.”。還有一個東西叫GLSurfaceView,這個是封裝好了的SurfaceView,也能夠配置HDR色域,而且吧這個控件游戲常用到,也就是說,HDR技術(shù)也可以落地到游戲上去。
一個有獨立的window,一個從屬于ViewRoot的window,所以SurfaceView為什么transform往往需要開發(fā)者自行開發(fā),但是ViewRoot早已預(yù)設(shè)了控件transform的能力,SurfaceTexture沿用就好。
到這里簡單描述一下我理解得的 常見的activity、surfaceview如何“承上”(承載App里各種view)了,接下來就是比較難的Android GUI的內(nèi)容了,我把它概括為啟下?把我們期待App的中各個區(qū)塊的內(nèi)容填充告訴到Android 系統(tǒng)服務(wù)。
啟下的起點就從surface開始吧,
上面我們提到了 surface,surface在我看來是兩個東西組成,一個是buffer queue,實現(xiàn)一套生產(chǎn)者消費者模式;一個是緩存,buffer queue傳送的東西,存儲著我們“承上”來的繪制或者素材數(shù)據(jù),比如我粗暴地理解成bitmap。
消費者生產(chǎn)者模式,我們的應(yīng)用、系統(tǒng)應(yīng)用、各種窗口生產(chǎn)出要上屏的內(nèi)容,這些內(nèi)容以surface的形式,交由給SurfaceFlinger進行整合生產(chǎn)出整塊屏幕顯示內(nèi)容給Display HAL層去上屏;怎么交由呢?surface中還有一個可以跟SurfaceFlinger系統(tǒng)服務(wù)打交道的代理,我們應(yīng)用的surface當然在我們應(yīng)用進程,要跟 SurfaceFlinger 打交道需要跨進程,所以不是即時的,我們常常說屏幕的刷新幀率多少,比如120hz屏幕,其實也對應(yīng)著SurfaceFlinger需要每秒鐘整合多少次屏幕內(nèi)容,或者我們可以理解成每1/120s,SurfaceFlinger就把這段時間,各個進程送來的上屏內(nèi)容收集,然后一層一層的摞起來,整合成一個整個屏幕的畫面數(shù)據(jù);SurfaceFlinger與Display HAL之間也有一個 buffer queue, 一個存放當前上屏數(shù)據(jù),一個存放著下一個上屏數(shù)據(jù),120hz屏幕每1/120s交替一次。
以上就是根據(jù)我的理解大致的描述發(fā)生在Android系統(tǒng)服務(wù)中上屏過程,如若有什么地方說的錯誤的,望指正;
那么HDR這個能力是怎么在Android的上屏過程中實現(xiàn)的呢?我通過上網(wǎng)查閱資料以及分析Dump下來的SurfaceFlinger的信息,大致腦補出了一個workflow,僅供參考:
首先,我們知道,對于上屏內(nèi)容處理,SurfaceFlinger處理的單元是Layer,確實每一Layer都有字段標識它是不是HDR以及HDR mode。
所以對于第三方開發(fā),我們需要做的就是把HDR信息配置到window上去,這個信息最終會配置到對應(yīng)的Layer上。Google Android Developer有介紹一些方法。https://developer.android.com/training/wide-color-gamut
然后我們知道SurfaceFlinger每次要處理很多Layer,一般UI layer的數(shù)據(jù)是8bit sRGB,而如果有一個layer是 10bit HDR RGB。與此同時平時廠商介紹手機的時候,色域的介紹基本上都是覆蓋P3 or DCI-P3色域百分之多少,其實也就是說,即使layer是 10bit HDR,其實就目前的手機屏幕支持的色域能力而言,我們手機也展示不了真實的BT 2020的色域下的表現(xiàn),是轉(zhuǎn)到了P3色域下的表現(xiàn)。所以在這個屏幕的廣色域模式下,任何顏色最終都是映射到P3色域上。
SDR的layer經(jīng)過一次 Color Gamut轉(zhuǎn)化,將BT709的顏色映射到P3的色域下;而HDR的layer除了需要經(jīng)歷Color Gamut轉(zhuǎn)化,將BT2020的顏色映射到P3的色域下之外還需要color-transfer的轉(zhuǎn)換,比如說PQ模式,由于屏幕硬件設(shè)備的Gamma值是固定的,假定是值a,芯片可以通過對PQ模式下Layer的RGB值乘上一個系數(shù),Color-Transfer(PQ)/ a , 最終也實現(xiàn)了對應(yīng)的Color-Transfer的作用,當然可能因為手機屏幕遠達不到HDR標準值的亮度值要求,Color-Transfer(PQ)值可能被優(yōu)化過,相較之下 iOS的HDR能力反而做的好得多。
接下來談下HDR跟屏幕之間的關(guān)系。
目前常常各大廠商PR稿在介紹屏幕能力的時候會著重強調(diào)自己的屏幕是OLED屏幕。其實OLED屏幕之前,主流的手機的屏幕是LCD屏幕。OLED屏幕雖然有很多被人吐槽的點,比如說燒屏、低頻PWM調(diào)光晃眼睛,但是它的發(fā)光特性卻非常適合HDR功能。OLED屏幕是屏幕整齊排布的是自行發(fā)光體,而LCD屏幕是屏幕排布的只是濾鏡元件,亮度通過背光實現(xiàn),有點像是皮影戲,后面打著大燈控制亮度,前面帶有顏色的濾鏡片控制顏色,這種背光的模式導(dǎo)致即使屏幕要顯示帶有黑色的畫面,但是黑色區(qū)域也不是真正的無光,只是相對的黑,但是OLED屏幕就可以控制黑色區(qū)域完全不發(fā)光就可以實現(xiàn)“極致的黑”,所以當分母為0,亮度比就可以非常非常大,所以O(shè)LED屏幕的亮度比遠大于LCD屏幕。而我們知道,HDR技術(shù)的目的是讓明暗細節(jié)都能在同一幀畫面中體現(xiàn)出來,OLED的屏幕的特性就與HDR目的非常契合,所以移動端的HDR技術(shù)常常和OLED屏幕聯(lián)系起來。
絮絮叨叨先說到這里了。