在移動(dòng)手機(jī)端VR應(yīng)用需要更多的組件支持。首先是傳感器能夠跟蹤記錄用戶(hù)頭部的運(yùn)動(dòng),CPU驅(qū)動(dòng)VR應(yīng)用程序(大多都是在后臺(tái)運(yùn)行),GPU負(fù)責(zé)處理和計(jì)算來(lái)生成正確的顯示圖像,向用戶(hù)或觀察者呈現(xiàn)變換后的內(nèi)容。
所有這些組件需要密切協(xié)作才能給用戶(hù)提供逼真的使用體驗(yàn)。眾所周知都會(huì)有一定延遲時(shí)間,這段時(shí)間被命名為“motion to photon latency”(即從用戶(hù)運(yùn)動(dòng)開(kāi)始到相應(yīng)畫(huà)面顯示到屏幕上所花的時(shí)間)。盡管它是一個(gè)專(zhuān)業(yè)術(shù)語(yǔ),但是卻很好的描述了問(wèn)題:伴隨用戶(hù)頭部的運(yùn)動(dòng),VR設(shè)備何時(shí)能夠意識(shí)到并給用戶(hù)展示正確的場(chǎng)景。
在真實(shí)世界中,這種情形很普遍以至于我們都沒(méi)有意識(shí)到——否則我們就會(huì)經(jīng)常走路撞墻了。然而將一個(gè)手機(jī)掛在頭部前端顯示VR場(chǎng)景,想要達(dá)到同樣的效果是非常困難的。原因有很多種:計(jì)算機(jī)運(yùn)行的時(shí)鐘頻率是固定的,流水線(xiàn)采用串行處理數(shù)據(jù),最明顯的就是最終圖像渲染花費(fèi)的時(shí)間。
我們作為一個(gè)GPU IP研發(fā)公司,當(dāng)然非常有興趣優(yōu)化我們的顯卡處理流水線(xiàn)以降低延遲,減少PowerVR顯卡處理器渲染最終顯示圖像所耗費(fèi)的時(shí)間。
對(duì)于Android系統(tǒng)和設(shè)備的組件要求
最終在安卓屏幕上顯示的內(nèi)容要采用組件的形式完成渲染。通常會(huì)有幾個(gè)廠(chǎng)家自定義符合自己要求的圖像,它們有自己的系統(tǒng)UI(顯示狀態(tài)欄和導(dǎo)航欄等)和前臺(tái)應(yīng)用程序(在設(shè)置的緩沖區(qū)中完成圖像的渲染)。
這些緩沖區(qū)會(huì)被一個(gè)“消費(fèi)者”線(xiàn)程所占用并且會(huì)直接反應(yīng)在屏幕的顯示效果上,大多數(shù)情況下在一個(gè)系統(tǒng)級(jí)應(yīng)用中這個(gè)“消費(fèi)者”線(xiàn)程通常被稱(chēng)為SurfaceFlinger服務(wù)。
如果硬件支持SurfaceFlinger就可以決定將這些緩沖區(qū)中渲染的圖像直接在屏幕上顯示(以正確的組織布局)。這個(gè)模式被稱(chēng)為硬件組件而且需要硬件顯示設(shè)備的直接支持。如果硬件顯示上不支持這個(gè)組織布局,SurfaceFlinger服務(wù)會(huì)采用一個(gè)幀緩沖器,利用GPU完成所有圖像的渲染并保存在幀緩沖器中,最后像正常情況一樣在顯示器上完成圖像組件的展示。
展示組件的處理過(guò)程
生成者線(xiàn)程和消費(fèi)者線(xiàn)程都是相互高度獨(dú)立的——實(shí)際上他們是不同的進(jìn)程,采用跨進(jìn)程的方式實(shí)現(xiàn)數(shù)據(jù)通信。現(xiàn)在如果一方出現(xiàn)錯(cuò)誤,就會(huì)出現(xiàn)混亂和意想不到的問(wèn)題。
舉個(gè)例子生產(chǎn)者對(duì)一個(gè)正在向用戶(hù)顯示的幀緩沖區(qū)進(jìn)行渲染操作,那么用戶(hù)就會(huì)產(chǎn)生視覺(jué)沖突,這種情況稱(chēng)為“撕裂”效應(yīng)。屏幕上的圖像一半是過(guò)時(shí)的內(nèi)容,而另一部分是重新經(jīng)過(guò)渲染的圖像。“撕裂”效應(yīng)很容易判別,因?yàn)槠聊簧蠒?huì)有明顯的切割線(xiàn)。
一個(gè)簡(jiǎn)單的動(dòng)畫(huà)展示“撕裂”效應(yīng)
為了防止“撕裂”效應(yīng),有兩個(gè)關(guān)鍵因素是必須的。首先就是各部分之間要保證適當(dāng)?shù)耐剑浯尉褪遣捎秒p緩沖技術(shù)。
同步操作可以采用安卓“Native Syncs”框架來(lái)實(shí)現(xiàn),這個(gè)框架的一些標(biāo)準(zhǔn)和規(guī)范讓它能夠應(yīng)用于安卓系統(tǒng),它們借助內(nèi)核空間來(lái)實(shí)現(xiàn)系統(tǒng)全局同步,在用戶(hù)模式下使用文件描述符可以實(shí)現(xiàn)不同進(jìn)程間的數(shù)據(jù)共享。
它們也是非復(fù)用的二進(jìn)制同步機(jī)制,僅有“無(wú)信號(hào)”和“有信號(hào)”兩個(gè)狀態(tài),并且只有一種狀態(tài)的轉(zhuǎn)換就是從“無(wú)信號(hào)”到“有信號(hào)”(狀態(tài)是不可逆的)。
雙緩沖技術(shù)可以實(shí)現(xiàn)在舊的圖像內(nèi)容正在被消費(fèi)者線(xiàn)程所占用的同時(shí),生產(chǎn)者可以渲染新的圖像內(nèi)容。當(dāng)生產(chǎn)者完成渲染操作,兩個(gè)緩沖區(qū)就會(huì)被轉(zhuǎn)換,消費(fèi)者則調(diào)用最新渲染的圖像內(nèi)容,與此同時(shí)生產(chǎn)者則開(kāi)始渲染剛剛還在被消費(fèi)者線(xiàn)程調(diào)用的圖像內(nèi)容。
上面這兩種機(jī)制都是必須的,這樣才能在安卓系統(tǒng)上實(shí)現(xiàn)流暢的圖像輸出,但是不幸的是這仍然還有額外的延遲花銷(xiāo)。
就在三月份Khronos Group組織發(fā)布了“KHR可變的渲染緩沖器EGL擴(kuò)展”規(guī)范,我們利用這個(gè)規(guī)范實(shí)現(xiàn)了上述單緩沖器渲染功能。
這個(gè)擴(kuò)展標(biāo)準(zhǔn)需要GPU驅(qū)動(dòng)和安卓操作系統(tǒng)的支持,正如我之前解釋的那樣,安卓系統(tǒng)很長(zhǎng)時(shí)間一直都組織這種模式的操作,因?yàn)檫@樣會(huì)產(chǎn)生圖像“撕裂”效應(yīng)。
那么當(dāng)我們使用新的單緩沖器技術(shù)模式時(shí)如何組織“撕裂”效應(yīng)的發(fā)生呢?
屏幕技術(shù)
回答這個(gè)問(wèn)題之前我們需要了解一下顯示器是如何工作的。GPU驅(qū)動(dòng)會(huì)向顯示器驅(qū)動(dòng)推送一個(gè)幀緩沖數(shù)據(jù)包,采用的數(shù)據(jù)格式是顯示器能夠解析的。這就可能對(duì)幀緩沖數(shù)據(jù)格式有不同的要求,例如特殊的形變或者紋理對(duì)齊。
顯示器會(huì)在下一畫(huà)面顯示新的幀緩沖圖像,假設(shè)顯示器從頂部到底部刷新新的圖像,“beam(刷新分割線(xiàn))”又從顯示器屏幕底部返回到頂部,“vsync”或者垂直同步能夠及時(shí)的實(shí)現(xiàn)就比較關(guān)鍵了。
很明顯現(xiàn)在“beam”已經(jīng)不再使用了,但是這種命名法仍然被采用。因?yàn)楝F(xiàn)在顯示器不會(huì)再?gòu)膸彌_器中取出任何數(shù)據(jù),我們完全可以直接切換新的圖像,并且確保不會(huì)出現(xiàn)“撕裂”現(xiàn)象。顯示器完成這個(gè)操作花費(fèi)的時(shí)間是固定的,與顯示器的時(shí)鐘周期相關(guān)。
通常一般的顯示器刷新周期是16.7ms,這意味著屏幕上的畫(huà)面每秒鐘可以刷新60次。
顯示器掃描加載過(guò)程
現(xiàn)在的手機(jī)通常采用16:9的顯示比例,屏幕都是安裝好的因此對(duì)掃描加載過(guò)程進(jìn)行了優(yōu)化,采用豎屏的加載模式,因?yàn)榇蠖鄶?shù)用戶(hù)每天都是這樣使用他們的手機(jī)的。
對(duì)于VR則不同,VR應(yīng)用則是橫向顯示,因此顯示器加載方向變成從左到右進(jìn)行。
因此讓我們看看如何更新幀緩沖器同時(shí)又要在屏幕上顯示,這是相當(dāng)重要的。
條帶式渲染
當(dāng)顯示器掃描加載緩沖器中的圖像時(shí),它的掃描加載速率通常是固定的。條帶式渲染技術(shù)則是改變緩沖器中未被顯示器掃描加載的那部分圖像數(shù)據(jù)。主要分為兩種不同的策略,在顯示器下一次掃描加載過(guò)程中改變屏幕顯示的部分畫(huà)面。
這個(gè)被稱(chēng)為光線(xiàn)追蹤,我們需要在掃描加載線(xiàn)的前面進(jìn)行渲染然后更新幀緩沖器中的內(nèi)容,這樣在顯示器屏幕上的內(nèi)容就會(huì)不同。另一種策略則是光線(xiàn)追趕,意思就是滯后掃描加載線(xiàn),更新其后面的內(nèi)容,正好與上一種策略相反。
光線(xiàn)追蹤技術(shù)能更好的解決延遲問(wèn)題,但是同時(shí)也更難實(shí)現(xiàn)。GPU需要保證在非常緊張的實(shí)現(xiàn)內(nèi)完成圖像渲染操作。這種保證在多進(jìn)程的操作系統(tǒng)中很難完成,因?yàn)榇蟛糠謶?yīng)用進(jìn)程都在后臺(tái)運(yùn)行,與此同時(shí)GPU還要完成另一個(gè)幀緩沖器的渲染任務(wù)。因此更為簡(jiǎn)單的實(shí)現(xiàn)方法則是光線(xiàn)追趕策略。
光線(xiàn)追趕策略實(shí)現(xiàn)條帶式渲染
VR應(yīng)用需要向顯示器請(qǐng)求最新一幀畫(huà)面的掃描加載時(shí)間,并實(shí)時(shí)調(diào)整自己以確保完成全屏幕的渲染任務(wù),然后再屏幕上呈現(xiàn)。為了計(jì)算一個(gè)條帶開(kāi)始渲染的時(shí)刻,首先我們需要定義條帶的尺寸。條帶的尺寸和條帶的數(shù)量是可以定義的,這取決于顯示器掃描加載的速度以及我們渲染每個(gè)條帶的所需要的時(shí)間。在大多數(shù)情況下一般采用兩個(gè)條帶式最優(yōu)的。在VR應(yīng)用中正好分為兩部分對(duì)應(yīng)人的左右眼(我們是從左向右進(jìn)行掃描加載),這樣實(shí)現(xiàn)起來(lái)就更加容易了。在下面的例子中我們使用四個(gè)條帶來(lái)向大家展示是如何工作的,前面提到過(guò)渲染整幅畫(huà)面的時(shí)間是16.7ms。
通常渲染每個(gè)條帶的時(shí)間可以是4.17ms。VR應(yīng)用在顯示完最后一幀畫(huà)面后等待4.17ms然后開(kāi)始渲染第一個(gè)條帶,渲染第二個(gè)條帶時(shí)則需要再等待4.17ms(則從開(kāi)始一共等待了8.34ms),重復(fù)這樣的操作直到四個(gè)條帶都完成渲染,然后開(kāi)始新一輪的操作。顯然我們需要考慮每幀渲染提交所用的時(shí)間,并適當(dāng)調(diào)整我們的時(shí)序,使用絕對(duì)時(shí)間證明是最準(zhǔn)確的方法。
渲染VR模擬圖像使用的條帶分離技術(shù)
最后的一點(diǎn)兒想法
降低移動(dòng)設(shè)備中VR應(yīng)用的延遲是現(xiàn)在開(kāi)發(fā)者面臨的重大挑戰(zhàn)之一。這不同于桌面的VR解決方案,桌面解決方案擁有更好的處理能力而且也不會(huì)遇到散熱問(wèn)題的限制。
評(píng)論