Android Skia iOS CoreGraphics Windows GDI/DX3D/DX2D Linux Cario AGG 等等都是大家常用的渲染器(Path Render, 這里的渲染器特指最終會(huì)通過算法做像素染色. 而不是不是Web前端提到的渲染, 兩者之間存在著本質(zhì)的差異),這些渲染器把程序提交的渲染Command(例如:DrawLine DrawArcTo..)最后轉(zhuǎn)化成了光柵圖,然后提交給硬件上屏就OK了.
那么實(shí)際上就是生成一張位圖而已?
可以這么理解, 操作系統(tǒng)或者程序就是不停的構(gòu)建當(dāng)前界面的位圖,在另一篇里面我介紹了硬件加速構(gòu)建UI的原理.
1. 打印機(jī)-曾經(jīng)的顯示器
計(jì)算機(jī)剛剛出現(xiàn)的時(shí)候沒有好用的輸出設(shè)備,最常用的是打印機(jī),對(duì)的你沒有聽錯(cuò)。打印機(jī)是曾經(jīng)的顯示設(shè)備,每次程序運(yùn)行結(jié)束后會(huì)通過打印機(jī)把結(jié)果打印出來。用過打印機(jī)的同學(xué)可能沒有注意到一個(gè)事實(shí):打印機(jī)是獨(dú)占設(shè)備(所謂獨(dú)占設(shè)備指的是在同一個(gè)時(shí)刻只能由一個(gè)程序持有該設(shè)備,其他程序只能等待直到能夠獲取到)。
后面終于可以用顯示器來實(shí)時(shí)顯示計(jì)算的繪圖結(jié)果了,極大解決顯示的成本。但是在早期的顯示系統(tǒng)架構(gòu)下顯示器也是獨(dú)占設(shè)備(和打印機(jī)一樣),也就是一個(gè)時(shí)刻只能由一個(gè)程序往顯示器輸出結(jié)果(是不是很傻@@@!)。隨著操作系統(tǒng)的發(fā)展,尤其是分時(shí)多任務(wù)(通過CPU切割時(shí)間片來實(shí)現(xiàn)的多任務(wù),也就是多線程的技術(shù))系統(tǒng)的發(fā)展。需要多個(gè)程序同時(shí)往屏幕輸出圖像(試想一下如果現(xiàn)在的顯示器還是獨(dú)占設(shè)計(jì),那么你在用chrome上網(wǎng)的時(shí)候沒有版本聊QQ了,寫Office的時(shí)候也不能切換到網(wǎng)易云音樂聽一段了),同時(shí)顯示多個(gè)程序的輸出可以極大的提升顯示器的利用率,也能極大的提升用戶的使用效率。
2. 如何讓多個(gè)程序同時(shí)繪制到屏幕上去
所以上面已經(jīng)闡述了,對(duì)于硬件驅(qū)動(dòng)測我們能做的就是提交給他那張渲染好的位圖,基本這個(gè)方式動(dòng)不了。所以我們在操作系統(tǒng)測這邊動(dòng)動(dòng)奶子~ 額 腦子哦!
首先從操作系統(tǒng)測接管了對(duì)顯示設(shè)備的控制,也就是顯示器交給了操作系統(tǒng)獨(dú)占,當(dāng)然這個(gè)時(shí)候有其他程序需要獨(dú)占顯示器有不太可能(現(xiàn)在也提供了獨(dú)占的方式,主要提供給游戲使用。獨(dú)占的好處是可以更快速的和硬件通訊,數(shù)據(jù)可以快速發(fā)送到屏幕上面并顯示給用戶)。
當(dāng)程序需要向屏幕繪制內(nèi)容的時(shí)候,首先向系統(tǒng)申請(qǐng)一個(gè)窗口然后系統(tǒng)會(huì)給這個(gè)窗口分配一塊RAM存儲(chǔ)空間(可以是內(nèi)存也可以是顯存),這個(gè)存儲(chǔ)空間可以看做是一個(gè)RGBA的二維數(shù)組(也就是一張位圖)。這樣程序只要把繪制的內(nèi)容繪制到這塊存儲(chǔ)空間上面去就好。那么當(dāng)有多個(gè)程序(進(jìn)程)同時(shí)需要繪制的話,那么系統(tǒng)這個(gè)時(shí)候其實(shí)就已經(jīng)分配了多個(gè)窗口。那么操作系統(tǒng)只要定時(shí)統(tǒng)計(jì)所有窗口的位圖,然后按照窗口的上下層疊順序通過AlphaBlend合并在一張位圖上,然后操作系統(tǒng)把這張合成后的位圖提交給顯示器顯示就好了。

3. 雙緩沖和三緩沖
上面多窗口的架構(gòu)確實(shí)能解決多進(jìn)程渲染到屏幕的問題,通過系統(tǒng)定時(shí)合并 多窗口分別渲染的方式解決。就按Android系統(tǒng)來說,這個(gè)窗口就叫做Surface而合并Surface的系統(tǒng)程序就叫做SurfaceFlinger。其他的操作系統(tǒng)以此類推。
但是存在一個(gè)問題:多窗口的RAM數(shù)據(jù)空間在被系統(tǒng)合并的時(shí)候,對(duì)應(yīng)渲染的程序不能操作這塊RAM數(shù)據(jù)(你想啊,如果系統(tǒng)正在把當(dāng)前這幀合并到屏幕上去,合并不是瞬時(shí)完成的啊,需要一定的時(shí)間啊。你的程序恰好在這個(gè)時(shí)間也在操作這幀的數(shù)據(jù)就會(huì)出現(xiàn)上下兩幀錯(cuò)位的情況)。這樣影響了軟件渲染的性能,畢竟不能真正的并行處理。當(dāng)系統(tǒng)在合并上屏的時(shí)候,程序如果需要繪制只能等待了,那么如何解決這個(gè)問題?
答案:程序在系統(tǒng)申請(qǐng)窗口系統(tǒng)可以分配2塊一模一樣的RAM空間,每塊RAM存儲(chǔ)空間都可以獨(dú)立存儲(chǔ)程序渲染的位圖。一塊位圖叫做前景圖另一塊叫后景圖。程序每次只能繪制到前景圖,當(dāng)程序繪制完當(dāng)前這幀的時(shí)候就會(huì)通知系統(tǒng)交換前后景圖(系統(tǒng)內(nèi)核只是交換了一下指針,成本非常低)。操作系統(tǒng)定期把后景圖合并上屏幕,通過這種雙緩沖的方式就可以讓系統(tǒng)合并上屏和軟件繪制并行處理,互相之間基本不影響。
總結(jié):系統(tǒng)自己持有了一張用來合并結(jié)果的位圖,每個(gè)程序在分配窗口的時(shí)候其實(shí)有2張位圖數(shù)據(jù)空間。這樣整個(gè)渲染系統(tǒng)基本上是由3張位圖數(shù)據(jù)共同作用。單純從軟件測來說叫雙緩沖。整個(gè)架構(gòu)體系又叫做三緩沖。
4. 多緩沖在操作系統(tǒng)的各種使用場景
操作系統(tǒng)利用多緩沖的方式把顯示設(shè)備從獨(dú)占設(shè)備改變到了共享設(shè)備。讓多個(gè)進(jìn)程可以同時(shí)渲染到顯示器上面,大大增強(qiáng)了顯示器這種外接設(shè)備使用效率。那么這類技巧還用在哪里?
答案: 硬盤,聲卡,網(wǎng)卡 等等都采用了類似的方案。
比如聲卡:傳統(tǒng)聲卡早期只支持一路聲音數(shù)據(jù)的播發(fā),也就是同一時(shí)刻只能播發(fā)一個(gè)程序的一個(gè)聲音(大白話)。現(xiàn)在的顯卡已經(jīng)支持有效多路(比如聲卡的接口支持同時(shí)輸入3路聲音的數(shù)據(jù))。但是有的時(shí)候我們的系統(tǒng)采用還是多緩沖的方式來解決這個(gè)問題。每個(gè)程序當(dāng)需要播發(fā)聲音的時(shí)候,就把聲音的數(shù)據(jù)(PCM編碼的聲音數(shù)據(jù))提交給系統(tǒng)。系統(tǒng)利用混音算法(顏色用的Alpha融合,聲音用的是混合算法)把多路混合成一路。得到這一路的數(shù)據(jù)后再丟給聲卡播發(fā)就好了(這類算法只要CPU的運(yùn)算性能足夠,理論可以同時(shí)播發(fā)任意路。當(dāng)你在看電影順帶聊著QQ,系統(tǒng)時(shí)不時(shí)還給點(diǎn)提醒聲音等等,就都可以同時(shí)播發(fā)了)。

那還有一點(diǎn)需要討論,屏幕在接受到系統(tǒng)的顯示位圖后,是如何顯示到屏幕的?
5. 屏幕刷新和VSYNC垂直同步型號(hào)
屏幕也是采用掃描線的算法來實(shí)現(xiàn)對(duì)屏幕顯示像素的刷新。比如常見的橫向掃描屏幕,屏幕就按照位圖的像素的數(shù)據(jù)從左到右,從上到下依次設(shè)置屏幕顏色的亮度。每一幀從第一個(gè)像素處理完到最后一個(gè)像素處理完成成為一幀刷新。那么刷新一幀需要多少時(shí)間?這個(gè)從顯示器出廠就定死了。比如常規(guī)的顯示器都是60HZ刷新率的(也就是一秒可以刷新60張),也有用于游戲的80HZ和144HZ的屏幕。
按照60HZ的刷新頻率來說,一幀數(shù)據(jù)從第一個(gè)像素到最后一個(gè)像素需要 1000ms/60 = 16ms的時(shí)間。如果屏幕刷新到一半的時(shí)候,系統(tǒng)提交了新的一幀數(shù)據(jù)。那么就會(huì)出現(xiàn)當(dāng)前屏幕顯示的,已經(jīng)刷新的一半內(nèi)容是上一幀的,后面的部分繪制下一幀的數(shù)據(jù),這樣的現(xiàn)象被叫做幀撕裂,甚至?xí)霈F(xiàn)屏幕閃爍。
那么系統(tǒng)如何在屏幕一幀完全刷新完成后才提交下一幀的數(shù)據(jù)?這就要說到垂直同步了。顯示器在刷新完一幀的時(shí)候回向系統(tǒng)提交一個(gè)叫VSYNC的信號(hào),系統(tǒng)受到這個(gè)硬件信號(hào)后才提交數(shù)據(jù)。同樣操作系統(tǒng)也模擬了類似這個(gè)信號(hào)功能的軟信號(hào),用來告知軟件渲染算法,減少不必要的多余的渲染(比如屏幕只有60HZ,那么我的軟件性能很好每秒可以渲染120幀,那么多出來的60幀就被丟棄了,這樣就導(dǎo)致了性能的浪費(fèi))。
6. 運(yùn)動(dòng)模糊

最后: 我們來探討下運(yùn)動(dòng)模糊具體是什么?不知道大家關(guān)注過這個(gè)問題么?電視機(jī)的28HZ大家就覺得很流暢,但是游戲60HZ了還是覺得有卡頓。這個(gè)問題主要原因就是存在于 運(yùn)動(dòng)模糊的原因。電視機(jī)的界面基本全是靠攝像機(jī)拍攝的結(jié)果,大家可以挨幀分析下攝像機(jī)拍攝的影片。你會(huì)發(fā)現(xiàn)其中有很多的幀是模擬的。這種運(yùn)動(dòng)模糊是由于攝像機(jī)的CCD芯片需要曝光時(shí)間導(dǎo)致的。也正是這種現(xiàn)象,讓人腦在看到這類視頻的時(shí)候回覺得非常流暢。但是游戲的每一幀都是程序生成的,每一幀都是精確的不存在這種運(yùn)動(dòng)模糊效果。所以游戲即使刷新頻率到60HZ大家也覺得沒有電視來的流暢。目前有些游戲通過渲染前后2幀的插值來模擬這種運(yùn)動(dòng)模糊,當(dāng)游戲里面有大場景的轉(zhuǎn)動(dòng)的時(shí)候效果會(huì)比傳統(tǒng)游戲更加流暢(當(dāng)然大家都在60HZ滿幀渲染的情況下的)。
總結(jié)下: 額~ 沒啥總結(jié)的,那就這樣吧!
</br></br>
版權(quán)所有,如有轉(zhuǎn)載請(qǐng)聯(lián)系我本人http://www.breakerror.com/archives/68-i.html