努比亞技術團隊原創內容,轉載請務必注明出處。
Android畫面顯示流程分析(1)
Android畫面顯示流程分析(2)
Android畫面顯示流程分析(3)
Android畫面顯示流程分析(4)
Android畫面顯示流程分析(5)
目錄截圖:
1. 前言
本文嘗試從硬件認識開始介紹Android的顯示系統是如何更新畫面的,希望能就android系統是如何更新畫面的問題,給讀者帶來一個感性認知。文中將嘗試解釋從App畫出一幀畫面到這幀畫面是如何到達屏幕并最終被人眼看到的整個過程,這其中會涉及硬件的一些基礎知識以及Android系統下一些重要的軟件基礎組件。本文將先分別介紹畫面顯示過程中所涉及到的重要組件及其工作原理,然后從Android app渲染第一幀畫面開始逐步串聯起各個組件,期望最終對于Android系統下畫面是如何顯示出來的給讀者一個宏觀的認識。本文適合對Android顯示系統有過一定了解的同學閱讀。由于文章較長,這里會分成10個章節,共五篇博文來介紹。
由于本文是通過閱讀各種文章及代碼,總結出來的,難免有些地方理解得不對,歡迎大家批評指正。
2. 顯示硬件基礎
無論軟件的架構設計多么高端大氣上檔次,最終都離不開硬件的支持,軟件的架構是建構在硬件的運行原理之上的,所以在討論軟件的各個設計之前我們有必要對顯示硬件的原理做一個初步的了解。
2.1. 常見顯示設備
LCD(Liquid Crystal Display)俗稱液晶。
液晶是一種材料,液晶這種材料具有一種特點:可以在電信號的驅動下液晶分子進行旋轉,旋轉時會影響透光性,
因此我們可以在整個液晶面板后面用白光照(稱為背光),可以通過不同電信號讓液晶分子進行選擇性的透光,此時在液晶面板前面看到的就是各種各樣不同的顏色,這就是LCD顯示畫面的原理。
有些顯示器(譬如LED顯示器、CRT顯示器)自己本身會發光稱為主動發光,有些(LCD)本身不會發光只會透光,需要背光的協助才能看起來是發光的,稱為被動發光。
其他一些主流的顯示設備:
CRT:陰極攝像管顯示器。 以前的那種大屁股電視機就是CRT顯示,它曾是應用最廣泛的顯示器之一,不過現在基本沒有在使用這種技術了。
OLED:有機發光二極管又稱為有機電激光顯示(Organic Light-Emitting Diode,OLED),OLED顯示技術具有自發光的特性,采用非常薄的有機材料涂層
和玻璃基板,可以做得更輕更薄,可視角度更大,并且能夠顯著節省電能。目前未成為主流,但是很有市場潛力,將來很可能取代LCD。
LED:主要用在戶外大屏幕
2.2. LCD的接口技術
VGA(Video Graphics Array)即視頻圖形陣列,具有分辨率高、顯示速率快、顏色豐富等優點。VGA接口不但是CRT顯示設備的標準接口,同樣也是LcD液晶顯示設備的標準接口,具有廣泛的應用范圍。相信很多朋友都不會陌生,因為這種接口是電腦顯示器上最主要的接口,從塊頭巨大的CRT顯示器時代開始,VGA接口就被使用,并且一直沿用至今。
HDMI(High Definition Multimedia Interface) 高清多媒體接口,是一種全數字化視頻和聲音發送接口,可以發送未壓縮的音頻及視頻信號。HDMI可用于機頂盒,DVD播放機、個人計算機、電視、游戲主機、綜合擴大機、數字音響與電視機等設備。HDMI可以同時發送音頻和視頻信號,由于音頻和視頻信號采用同一條線材,大大簡化系統線路的安裝難度。
DVI(Digital Visual Interface),即數字視頻接口。它是1998年9月,在Intel開發者論壇上成立的,由Silicon Image、Intel(英特爾)、Compaq(康柏)、IBM(國際商業機器公司)、HP(惠普)、NEC(日本電氣股份有限公司)、Fujitsu(富士通)等公司共同組成的DDWG(Digital Display Working Group,數字顯示工作組)推出的接口標準
LVDS(Low Voltage Differential Signaling,即低電壓差分信號)接口又稱RS-644總線接口,是20世紀90年代才提出的一種數據傳輸和接口技術。LVDS接口是美國NS美國國家半導體公司為克服以TTL電平方式傳輸寬帶高碼率數據時功耗大,電磁干擾大等缺點而研制的一種數字視頻信號傳輸方式。由于其采用低壓和低電流驅動方式,因此,實現了低噪聲和低功耗。LVDS技術具有低功耗、低誤碼率、低串擾和低輻射等特點,其傳輸介質可以是銅質的PCB連線,也可以是平衡電纜。LVDS在對信號完整性、低抖動及共模特性要求較高的系統中得到了越來越廣泛的應用,常見于液晶電視中。
MIPI(Mobile Industry Processor Interface)是2003年由ARM, Nokia, ST ,TI等公司成立的一個聯盟,目的是把手機內部的接口如攝像頭、顯示屏接口、射頻/基帶接口等標準化,從而減少手機設計的復雜程度和增加設計靈活性。MIPI聯盟下面有不同的WorkGroup,分別定義了一系列的手機內部接口標準,比如攝像頭接口CSI、顯示接口DSI、射頻接口DigRF、麥克風/喇叭接口SLIMbus等。統一接口標準的好處是手機廠商根據需要可以從市面上靈活選擇不同的芯片和模組,更改設計和功能時更加快捷方便。
目前手機屏幕和SOC間多使用MIPI接口來傳輸屏幕數據,其實物如下圖所示,圖中的條狀芯片就是負責更新顯示屏的顯示內容的芯片DDIC, 它一邊通過mipi協議和SOC通信,一邊把獲取到的顯示數據寫入到顯示存儲器GRAM內, 屏幕(Panel)通過不停掃描GRAM來不停更新液晶顯示點的顏色,實現畫面的更新。
屏幕坐標系
顯示屏幕采用如下圖所示的二維坐標系,以屏幕左上角為原點,X方向向右,Y軸方向向下,屏幕上的顯示單元(像素)以行列式整齊排列,如下圖所示,如下圖示中以六邊形塊來代表一個像素點,如無例外說明,本文中所有圖示都將以該六邊形塊來代表屏幕上的一個像素點。
在一個典型的Android顯示系統中,一般包括SOC、DDIC、Panel三個部分, SOC負責繪畫與多圖層的合成,把合成好的數據通過硬件接口按某種協議傳輸給DDIC,然后DDIC負責把buffer里的數據呈現到Panel上。如下圖所示為高通平臺上的畫面更新簡單示意圖,首先CPU或GPU負責繪畫,畫出的多個layer交由MDP進行合成,合成的數據通過mipi協議和DSI總線傳輸給DDIC, DDIC將數據存到GRAM內(非video屏), Panel不斷scanGRAM來顯示內容。
那么對于DDIC來講它的職責就是按mipi協議和SOC交互,獲取到從SOC合成好的一幀畫面的數據,然后將數據寫入GRAM,對GRAM的寫入要符合一定的時序。
2.3. LCD時序
這個寫入時序要首先從過去的 CRT 顯示器原理說起。CRT 的電子槍按照從上到下一行行掃描,掃描完成后顯示器就呈現一幀畫面,隨后電子槍回到初始位置繼續下一次掃描。為了把顯示器的顯示過程和系統的視頻控制器進行同步,顯示器(或者其他硬件)會用硬件時鐘產生一系列的定時信號。當電子槍換到新的一行,準備進行掃描時,顯示器會發出一個水平同步信號(horizonal synchronization),簡稱 HSync;而當一幀畫面繪制完成后,電子槍回復到原位,準備畫下一幀前,顯示器會發出一個垂直同步信號(vertical synchronization),簡稱 VSync。顯示器通常以固定頻率進行刷新,這個刷新率就是 VSync 信號產生的頻率。盡管現在的設備大都是液晶顯示屏了,但原理仍然沒有變。
CLK:像素時鐘,像素數據只有在時鐘上升或下降沿時才有效
ENB:是數據使能信號,當它為高時,CLK信號到達時輸出有效數據。
HBP:行同步信號的前肩,水平同步信號的上升沿到ENABLE的上升沿的間隔。
HSW:水平同步信號的低電平(非有效電平)持續時間
HFP:行同步信號的后肩,ENABLE的下降沿到水平同步信號的下升沿的間隔 如下圖所示
圖中從HSYNC的下降沿開始,等待兩個CLK產生一個上升沿,在等待一個HBP時間后開始傳輸一行的像素數據,像素數據只有在像素時鐘和上升沿或下降沿時才會寫入(這里我們只討論原理,并不是某個特定平臺的具體實現,所以HSW所對應的時鐘數字并不是以圖中所示為準,具體產品中都會有調整和變化),經過N個像素時鐘后成功將一行像素數據寫入D1-Dn
類似地,在兩幀畫面之間也存在一些間隔:
VSW: VSYNC信號下降沿到上升沿間的時間
VBP: 幀同步信號的前肩
VFP:幀同步信號的后肩
VPROCH: 被稱為消隱區,它是指 VSW+VBP+VFP , 這個時間段內Panel不更新像素點的顏色
在一個Vsync周期內是由多個Hsync周期組成的,其個數就是屏幕在Y方向的像素點個數,也就是屏幕上有多少行像素點, 每個Hsync周期內傳輸一行內所有像素點的數據。通常屏廠給的spec文檔還會給出類似下面這樣的圖,但都是表達一個意思,數據是以行為單位寫入的,Hsync是協調行和行之間的同步信號,多個行依次寫入構成一幀數據,幀和幀數據之間由Vsync信號來同步協調。
當多幀畫面依次輸出到屏幕的時候我們就可以看到運動的畫面了,通常這個速度到達每秒60幀時人眼就已經感覺畫面很流暢了。下圖演示了在vsync和hsync同步下兩幀畫面間的切換時序,以及消隱區(VPorch)在其中的位置關系。在消隱區結束(或開始)時DDIC會向SOC發出一個中斷信號,這個信號稱為TE信號, SOC這邊就是通過該中斷信號來判斷上一幀數據是否已被DDIC讀走,進而決定是否可以將buffer寫入下一幀數據。
2.4. LCD上的畫面更新流程
讓我們以下面這張圖來說明從SOC到到DDIC再到Panel的畫面更新過程,首先SOC準備畫面A, DDIC上一幀畫面更新完畢進入消隱區,同時向SOC側發送TE信號,SOC收到TE信號后,A畫面的數據開始通過DSI總線向DDIC傳輸(DSI Write),當消隱區時間結束時開始這一幀數據從數據變為像素點顏色的過程(Disp Scan), Disp Scan是以行為單位將GRAM內一行的數據內容通過改變電流電壓等方式改變Panel上像素點的顏色。進而實現一行畫面的更新,按下來Disp Scan將以一定速度逐行讀取GRAM的內容,而于此同時DSI Write也還在進行中,由于DSI Write較Disp Scan早了一個Vporch的時間,所以Disp Scan掃描到的數據都是A畫面的數據。那么人眼會看到畫面“逐漸”出現到顯示屏上,當A畫面的所有行都經Disp Scan到達屏幕后,下一個Vporch開始,DDIC再次向SOC發出TE信號, 下幀B畫面的數據開始經過DSI總線傳輸到DDIC, 如此循環往復可以將連續的A, B, C畫面更新到屏幕上。
這里我們思考一個問題: 就像上圖中所繪一樣總會存在一段時間GRAM內的數據會出現一部分是新畫面的數據,一部分是舊畫面的數據,那么從上帝視角看GRAM里的畫面是“撕裂”的,那Disp Scan會不會把這個“撕裂”的畫面顯示到Panel上呢? 用戶有沒有可能看到一個“撕裂”的畫面呢?
答案是有可能會。
為討論方便我們這里先把DSI write記作寫, 把Disp Scan記作讀, 正常情況下,我們會將讀速度調到和寫速度差不多,由于寫是在進入vporch時就開始了,而讀的動作是離開vproch時,所以在讀和寫的這場“百米跑”競賽中總是寫跑在前面,這樣保證讀始終讀到的是同一幀畫面的數據,這個過程如下面圖1所示。
由于讀和寫的速度受到環境或各種電氣因素影響并不是一成不變的,在實際運行過程中會有波動,當讀和寫兩條線離的較近時由于速度波動的存在會出現兩條線交叉的情況,如圖2所示,那么這時讀會先后讀到前后兩幀的數據,出現花屏現象。
有時我們為了避免由于速率波動引起花屏問題,會放大vporch的時間讓讀和寫盡量拉開距離,這樣可以減少花屏現象出現的概率,這里的原理如圖3所示
繼續思考下一問題: 從上面的分析可以看出Panel上的像素數據是一行行更新下來的,那人眼為什么沒有看到更新了一半的畫面呢?
這個問題我并不知道答案,這可能涉及到人眼的生物學構造,人眼對事物的成像原理等復雜的原理,總之是在這個時間尺度內人眼看不到。
接下來我們從另一角度來研究一下這個問題,我們把視角切換到上帝視角,假如存在上帝之眼的話,他應該能看到這個更新了一半的畫面,我們嘗試用高速攝影機來模擬“上帝之眼”。
首先我們先準備一些測試代碼, 我們寫一個測試用apk, 下面這段代碼是向Android框架注冊一個Choreographer的監聽,Choreographer是Android提供的一個獲取vsync信號的通道。當下圖中doFrame被調用到時我們這里可以暫時粗略理解為是上面所討論的TE信號, 這里收到Vsync信號后通過Pthread的Condition通知到另一線程。這用于模擬一個vsync的消息泵。
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {//當vsync信號來時會調用到這里
Global.lock.lock();
try {
Global.syncCondition.signal();//通知另一條線程更新畫面
} catch (Exception e) {
e.printStackTrace();
} finally {
Global.lock.unlock();
}
Choreographer.getInstance().removeFrameCallback(this);
Choreographer.getInstance().postFrameCallback(this);
}
});
下面代碼中每收到一個vsync信號都會去畫一幀畫面,同時給幀編號編號加1(相當于給每一幀一個編號),如果當前的編號為奇數則畫綠色,如果為偶數則畫藍色,那么畫面應該是藍綠交替出現:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
.......
@Override
public void run() {
while(true) {
Global.lock.lock();
try {
Global.syncCondition.await();//在這里等待vsync到來的通知消息
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Global.lock.unlock();
}
draw();//畫藍色或綠色
}
}
........
private void draw() {
Canvas mCanvas = null;
try {
mCanvas = mSurfaceHolder.lockCanvas();
if(autoNum %2 == 0) {
mPaint.setColor(Color.BLUE);//如果為雙數則畫面畫成藍色
} else {
mPaint.setColor(Color.GREEN);//如果為單數則畫面畫成綠色
}
mCanvas.drawRect(0, 0, getRight(), getBottom(), mPaint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
autoNum++;//數字加1
}
}
下面是高速攝影機看到的畫面變化情況,從下圖中可以看出來,畫面從綠變藍的過程中總是能看到先是上面部分變藍色,接下來才會看到全部變藍,由藍變綠也是同樣的現象,先是圖像上面變成綠色接下來全部變綠色,在“上帝之眼”看來畫面的變化是有前后兩個畫面各占一部分的情況的,這情況是上面是新畫面下面是舊畫面,但人眼是看不出來這種畫面。
下面的圖中發現畫面是顏色漸變的,這是因為通過高速攝影機是畫面再次感光形成的影像,由于物理世界中光線是有衍射及曝光時長因素的,所以最終在高速攝影機留下的圖中是顏色漸變的。
2.5. 本章小結
在本章節中,我們了解到了一些顯示硬件的一些組成要件,以及屏幕是如何按時序更新畫面的,以及在畫面更新過程中屏和SOC間的一些互動是如何完成的。那么接下來我們再來了解下SOC內部是如何把畫面送過來的。