http:///2017/05/21/VSync%E4%BF%A1%E5%8F%B7/
在我們詳細分析SurfaceFlinger之前要了解一下VSync信號,為下一節(jié)分析Vsync工作原理打下基礎(chǔ)。 VSync信號相關(guān)首先我們要了解以下幾個概念: 屏幕刷新率即 Refresh Rate 或 Scanning Frequency,單位赫茲/Hz,是指設(shè)備刷新屏幕的頻率,該值對于特定的設(shè)備來說是個常量,如 60hz。
每一臺CRT顯示器都有自己的刷新率,其單位是Hz,其數(shù)值是顯示器每秒鐘更新畫面的次數(shù)。不同的顯示器支持再不同分辨率下的不同刷新率。它的范圍可以從低到60高到100。注意它不是你游戲中所提到的那個FPS。如果你設(shè)置了一個特定的刷新率,顯示器將一直按照這個速率刷新畫面。甚至畫面沒有任何的改變。
如下圖,屏幕的刷新過程是每一行從左到右(行刷新,水平刷新,Horizontal Scanning),從上到下(屏幕刷新,垂直刷新,Vertical Scanning)。當整個屏幕刷新完畢,即一個垂直刷新周期完成,會有短暫的空白期,此時發(fā)出 VSync 信號。所以,VSync 中的 V 指的是垂直刷新中的垂直/Vertical。 對于一個特定的設(shè)備,幀率和刷新頻率沒有必然的大小關(guān)系。 幀率即 Frame Rate,單位 fps,是指 gpu 生成幀的速率,如 33 fps,60fps,越高越好。 我想這里的每一人都明白FPS。它顯示顯示卡在每秒鐘可以描畫多少畫面。這顯然是越高越好。但是對于快速變化的游戲而言,你的FPS很難一直保持同樣的數(shù)值,他會隨著你所看到的顯示卡所要描畫的畫面的復(fù)雜程度而變化。 VSync
安卓系統(tǒng)中有 2 種 VSync 信號:屏幕產(chǎn)生的硬件 VSync 和由 SurfaceFlinger 將其轉(zhuǎn)成的軟件 Vsync 信號。后者經(jīng)由 Binder 傳遞給 Choreographer。 顯示器參數(shù)
TFT LCD 有 vsync,hsync,hspw,hbpd,hfpd, vspw,vbpd, vfpd 等參數(shù),這些參數(shù)都是由以前的 CRT(陰極射線顯像管)帶過來的, 而 TFT 液晶跟 CRT 顯示方法根本不同, 至于為什么這些參數(shù)也會引入到 TFT 中,大概是因為VGA(或是DVI)工作原理,上文提到過。
CRT 側(cè)面看是個漏斗狀的真空的東東, 根部就是電子槍, 打出的電子撞擊前面的玻璃面上的熒光物質(zhì), 熒光物發(fā)光. 控制電子槍按規(guī)律射出電子, 逐行的打到熒光物質(zhì)上, 打完一行(也即掃描完一行), 就回頭掃描下一行….. 掃描完一個顯示屏所有的行后, 就是一幅完整的畫面了, 稱為一幀(frame), 掃描過程如果非常快, 人眼看到是一幅完整畫面, 但實際是一個個點發(fā)不同光組成的. 掃描得慢時, 就會覺得閃爍了(以前聽老師講課, 說在他們的年代, 能明顯看到一行一行刷過的壯觀場景)。 描述方式多數(shù)顯示器選擇從左上角開始, 從左至右, 到了右邊界, 再偏轉(zhuǎn)到左邊界的下一行, 這是所謂的”Z”型掃描。類似地掃描完最后一幀時, 要偏轉(zhuǎn)回左上角起始處, 準備掃描下一幀。這個上面那一幅圖描述過了。
H for Horizontal, V for vertical。在這里 Hsync, Vsync 兩者各表示一種信號, 分別由 HSPW 及 VSPW 兩個參數(shù)確定信號持續(xù)時間, 也就是脈沖的寬度. 在掃描一行中, 首先
因此, 顯示一行時序為: HSPW -> HBPD -> 掃描數(shù)據(jù) -> HFPD . 類似地, 垂直掃描一幀的時序:VSPW -> VBPD -> 掃描有效行 -> VFPD .
為什么要有邊框(vbpd, vfpd, hbpd, hfpd)? 按上邊貼出網(wǎng)頁的說法: 舉個栗子
對于 TFT LCD, 但這些參數(shù)作用是同樣的. 但如何確定 ? TFT 的 LCD 的 datasheet 中一定得標有。 對照下邊的時序圖(注: 時序圖的 Vsync, Hsync 信號(紅框圈出的)跟上邊講的有點出入, 信號都是低電平, 而非高電平, 因此編程時要設(shè)置信號反相, 如s3c244a 的 LCDCON5的INVLINE 及 INVFRAME 即是干這活的):
參考的時鐘就是 CLK, 一個 CLK 時鐘, 完成一個像素點的顯示。 計算幀頻率(刷新頻率)的方法就是所有的像素點跟邊沿(邊框,hbpd 之類),同步脈沖的時間相加, 結(jié)果就是顯示完整一幀所需時間, 其倒數(shù)即是幀頻率。 Linux 的 LCD 驅(qū)動
LCD 驅(qū)動主要得完成兩部分, 一是跟 framebuffer 注冊驅(qū)動; 二是設(shè)置 LCD 控制器的寄存器, 以適配 LCD。
struct fb_fix_screeninfo 里定義的 pixclock 是像素點的周期, 單位是皮秒, 數(shù)值等于像素點顯示頻率的倒數(shù). 如上圖貼出的表格中, Dclk 那行中, 6.4 Mhz 就是頻率, 頻率倒數(shù)即為周期, 換算出來為 156250 ps, 約為表中給出的 156 ns. 驅(qū)動具體的實現(xiàn), 要看開發(fā)板對應(yīng)的驅(qū)動源碼文件, 一般位于 kernel_src/drivers/video/ 下,我們以前下的Android源碼,找到對應(yīng)設(shè)備分支下的,應(yīng)為位于kernel/{branch}/drivers/video/吧。 簡單描述在手機平臺,LCD,Camera,TV的接線上,都會用到PCLK,VSYNC和HSYNC這三個信號。可見這三個信號和顯示關(guān)系非常大。首先我們先看這三個信號的作用:
若要顯示一個640x480的畫面,顯示不正確的時候,若量PCLK,VSYNC和HSYNC這三個信號,就可以知道這三個信號配置是否有問題,一般來講,這種情況是有公式的:
sensor的同步信號可以簡單的理解為sensor向其信號接收端所發(fā)送的宣告信號。比如HSYNC,就是sensor這告訴接收端:“HSYNC”有效時段內(nèi)sensor所有的信號輸出屬同一行。VSYNC同理,以高電平有效為例,VSYNC置高直到被拉低,這個區(qū)段sensor所輸出的所有影像數(shù)據(jù)組成一個frame。同步信號的頻率決定于pixel clock,比如一行有640個pixel,那么HSYNC的頻率為:PCLK/(640+dummy);Vsync同理。
VSync 信號的作用tearing 畫面撕裂首先,我們來看下,沒有引入 VSync 時,屏幕顯示圖像的工作流程。 如上圖,CPU/GPU 向 Buffer 中生成圖像,屏幕從 Buffer 中取圖像、刷新后顯示。這是一個典型的生產(chǎn)者——消費者模型。理想的情況是幀率和刷新頻率相等,每繪制一幀,屏幕顯示一幀。而實際情況是,二者之間沒有必然的大小關(guān)系,如果沒有鎖來控制同步,很容易出現(xiàn)問題。 所謂”撕裂”就是一種畫面分離的現(xiàn)象,就象你照一張照片,在旋轉(zhuǎn)哪怕一度再照一張照片,然后把兩張照片的從中間裁開,用一張照片的上半部與另一張的下半部對接起來。這樣得到的畫像雖然相似但是上半部和下半部確實明顯的不同。這就被稱之為視覺現(xiàn)實上的撕裂。它不會一直從中間分開,它可能靠近上面也可能下面,分離點可能在屏幕上下移動,也可能在兩點間前后移動。(譯者:原文的作者實在是啰嗦,其實就是畫面移動較快的時候,畫面看上去是兩截。這種現(xiàn)象恐怕打游戲的都看到過,最好玩過PS2游戲的,用模擬器,在比較差的顯卡和CPU上面,撕裂現(xiàn)象更為明顯)。 為什么會發(fā)生這種現(xiàn)象呢?讓我們舉一個特定的例子。讓我們假定你的顯示器的刷新率是75Hz, 你真在玩你最喜歡的游戲,而且你現(xiàn)在有100的FPS.這就意味著你的顯示器每秒更新75次畫面,而你的顯示卡每秒更新100次,比你的顯示器快33%。這就意味著在你的顯示器更新畫面的時間里,顯示卡描畫了1+1/3的畫面。這樣在畫面顯示的時候,那個1/3的畫面就會覆蓋那個完整畫面上部的1/3。在下次的圖像刷新的時候,顯示卡會描畫剩下來得2/3和新的2/3的畫面。這樣,因為屏幕的更新只能跟上畫面更新的2/3,這樣圖像的上部的1/3或是下部的1/3就會和剩下的畫面合不上。如果畫面的變化不大可能不太會注意到這一點,但是如果你快速的環(huán)顧四周那就會非常的明顯。 Double Buffer 雙緩沖現(xiàn)在,一個很普遍的誤解就產(chǎn)生了。一些人認為解決這個問題的方法就是簡單設(shè)置一個FPS的限制讓FPS不超過顯示器的刷新率,這樣顯示卡就不會超過75FPS,這樣就可以了。真的嗎?錯! 在我解釋為什么之前,讓我來講一下雙倍緩沖。雙倍緩沖一種用來減輕撕裂問題,雖然不是很完全。基本上來說你有一個顯示緩沖和一個后備緩沖。當顯示器要顯示畫面的時候,就會從顯示緩沖里“推出”顯示畫面。顯示卡則在后備緩沖里描畫另外一個新畫面,當描畫完成后則將新畫面考入顯示緩沖里。但是這個過程需要時間,如果顯示器的刷新在拷貝過程中進行的話,顯示器上顯示的仍然是個”撕裂”的畫面。 VSync 通過建立一個不讓在顯示器刷新前將后備緩沖中的畫面拷貝到顯示緩沖中的規(guī)定來解決這個問題。如果FPS高于刷新率的話,沒有問題。后備緩沖的更新完成后,系統(tǒng)處于等待狀態(tài)。當顯示器刷新后,后備緩存考入顯示緩存,顯示卡則可以在后備緩存里描畫新的畫面,這樣就很有效的將你的FPS限制在顯示器的刷新率的范圍內(nèi)。 為了解決單緩存的“tearing”問題,雙緩存和 VSync 應(yīng)運而生。雙重緩存模型如下圖: 兩個緩存區(qū)分別為 Back Buffer 和 Frame Buffer。GPU 向 Back Buffer 中寫數(shù)據(jù),屏幕從 Frame Buffer 中讀數(shù)據(jù)。VSync 信號負責(zé)調(diào)度從 Back Buffer 到 Frame Buffer 的復(fù)制操作,可認為該復(fù)制操作在瞬間完成。其實,該復(fù)制操作是等價后的效果,實際上雙緩沖的實現(xiàn)方式是交換 Back Buffer 和 Frame Buffer 的名字,更具體的說是交換內(nèi)存地址(有沒有聯(lián)想到那道經(jīng)典的筆試題目:“有兩個整型數(shù),如何用最優(yōu)的方法交換二者的值?”),通過二進制運算“異或”即可完成,所以可認為是瞬間完成。(《數(shù)字電路技術(shù)》當中有一章節(jié)應(yīng)該講過運算器還是控制器來著,可以設(shè)計一個異或電路。忘了,回去翻一翻~)
雙緩沖的模型下,工作流程這樣的: 在這種模型下,只有當 VSync 信號產(chǎn)生時,CPU/GPU 才會開始繪制。這樣,當幀率大于刷新頻率時,幀率就會被迫跟刷新頻率保持同步,從而避免“tearing”現(xiàn)象。 Jank 掉幀注意,當 VSync 信號發(fā)出時,如果 GPU/CPU 正在生產(chǎn)幀數(shù)據(jù),此時不會發(fā)生復(fù)制操作。屏幕進入下一個刷新周期時,從 Frame Buffer 中取出的是“老”數(shù)據(jù),而非正在產(chǎn)生的幀數(shù)據(jù),即兩個刷新周期顯示的是同一幀數(shù)據(jù)。這是我們稱發(fā)生了“掉幀”(Dropped Frame,Skipped Frame,Jank)現(xiàn)象。 讓我們來看一個另外一個不同的例子。讓我們假定你已經(jīng)玩到了你最喜歡的游戲的最后一關(guān),這個游戲有很好的圖像.你顯示器的刷新率還是在75。但是你的FPS現(xiàn)在只有50了,比刷新率要低33%.這就意味著每次顯示器刷新圖像,你的顯示卡只能畫出下一楨畫面的2/3。讓我們看看它是如何工作的。
如此類推。這樣4次顯示器刷新,我們只能的到2楨的畫面。如果刷新率是75的話,我們只能得到35的FPS.很明顯這個數(shù)值要低于顯示卡可以帶到的50FPS.這主要就是應(yīng)為顯示卡不得不在描畫后備緩沖上浪費時間。而在此過程中,后備緩沖上的畫面是不能被拷貝到顯示緩沖。理論上講,雙緩沖的VSync,FPS將是一組不連續(xù)的整數(shù),其等于刷新率/n,n是正整數(shù)。也就是說,如果你的刷新率是60hz,你能得到的FPS只能是 60,30,20,15,12,10 等等。你可以注意到60到30是一個相當大的差距。只要的顯示卡的FPS在60到30之間,你說得到的真實FPS都將只能等于30! 如下圖,A、B 和 C 都是 Buffer。藍色代表 CPU 生成 Display List,綠色代表 GPU 執(zhí)行 Display List 中的命令從而生成幀,黃色代表生成幀完成。 現(xiàn)在,你明白為什么有人不喜歡它了。讓我們回到一開始的那個例子。你在玩你最喜歡的游戲,刷新率是75HZ,100FPS。你打開VSync.游戲就被限制在75FPS,沒有問題,沒有撕裂圖像,看起來不錯。你到了一個圖像特別復(fù)雜的地方,在不用VSync的時候,你的FPS下降到了60左右。但是你打開了VSync,你的FPS實際就只有37.5。這樣你的游戲突然從75FPS變成了37.5FPS,不管37.5仍然很流暢但是你一定會注意到刷新率突然減少了一半。當讓如果以下變到25FPS的話,實際的現(xiàn)實率可能就只有17.5。本來還可以玩的游戲,就變成了幻燈片。這就是大家不喜歡它的原因。 如果你的游戲的FPS可以一直穩(wěn)定的大于顯示器的刷新率,VSync是個不錯的東西。但是如果FPS忽大忽小。VSync就是讓人煩的東西。如果你的游戲FPS一直都小于刷新率的話,實際的FPS要遠遠小于顯示卡可以顯示的FPS.看上去就象是VSync降低了你的FPS,但是從技術(shù)角度講,不是應(yīng)為圖像太復(fù)雜,而是因為VSync就是這樣工作的。 Triple Buffer 三緩沖雙重緩存的缺陷在于:當 CPU/GPU 繪制一幀的時間超過 16 ms 時,會產(chǎn)生 Jank。更要命的是,產(chǎn)生 Jank 的那一幀的顯示期間,GPU/CPU 都是在閑置的。 也不是說所有的希望都沒有了?,F(xiàn)在的triple-buffering技術(shù)可以用來解決這個問題。讓我們再來看刷新率75。FPS50的例子。
也就是刷新率的2/3,也就是50FPS.triple-buffering理論上講可以避免緩沖寫入是帶來的延遲現(xiàn)象,這樣就不會浪費時間。但是triple-buffering并不是適用于所有的游戲。實際上它并不是普及(這個文章可能寫的太早,現(xiàn)在triple-buffering已經(jīng)很普及了),而且它也會影響顯示卡的性能,應(yīng)為它需要更多的顯示內(nèi)存,需要更多時間在內(nèi)存之間降數(shù)據(jù)拷貝來拷貝去。但是triple-buffering確實是一個很好的方法,既可以消除撕裂畫面又可以不像普通VSync一樣影響你的FPS. 如果有第三個 Buffer 能讓 CPU/GPU 在這個時候繼續(xù)工作,那就完全可以避免第二個 Jank 的發(fā)生了! 于是就有了三緩存:
工作原理同雙緩沖類似,只是多了一個 Back Buffer。 三緩沖局限
我希望這篇文章是有用的,可以幫出你理解VSync的工作原理。(特別是不再猶豫是否打開VSync)總之,如果沒有triple-buffering的情況下,如何權(quán)衡Vsync的FPS限制和消除撕裂畫面帶來的視覺感受,那將完全取決于你個人的喜好。
所以一定會有人問:液晶顯示器的刷新頻率為何不能調(diào)高? 參考
Getting To Know Android 4.1, Part 3: Project Butter - How It Works And What It Added 總結(jié)本篇科普一下VSync,下一節(jié)開始分析它在SurfaceFlinger中的工作流程。 |
|
來自: astrotycoon > 《vsync》