對(duì)于延遲,不同的人有著不同的衡量方法。例如,從按下按鈕到解碼器予以識(shí)別的時(shí)間;從系統(tǒng)渲染一陣到屏幕進(jìn)行顯示的時(shí)間等等。Oculus的測(cè)量方法則是,從游戲邏輯采樣預(yù)測(cè)追蹤到利用這一游戲狀態(tài)渲染的一幀呈現(xiàn)在屏幕中的時(shí)間。
對(duì)于傳統(tǒng)的游戲幀,一開(kāi)始都是采樣輸入,執(zhí)行所有邏輯更新,將所有對(duì)象渲染到幀;然后,用前置緩存交換后置緩存,從而在屏幕顯示全新的一陣。對(duì)于為傳統(tǒng)顯示器設(shè)計(jì)的游戲,它們可能會(huì)嘗試維持穩(wěn)定的幀速率,如30fps或60fps。但丟失的一幀通常會(huì)被忽略,因?yàn)橛螒蛑械腸amera位置和旋轉(zhuǎn)與真實(shí)世界的顯示器位置和旋轉(zhuǎn)隔離。對(duì)于VR,丟幀會(huì)對(duì)用戶(hù)的舒適度產(chǎn)生嚴(yán)重影響,因?yàn)橹灰秩臼澜缗c現(xiàn)實(shí)世界不匹配,沉浸幻覺(jué)就會(huì)被打破。所以,Oculus提供了一個(gè)名為異步時(shí)間扭曲(Asynchronous TimeWarp)的系統(tǒng),利用最近渲染的一幀,并在屏幕顯示之前對(duì)其進(jìn)行修改,從而令眼睛視圖盡可能接近相應(yīng)的真實(shí)世界方向。
這意味著Oculus的渲染管道存在略微的不同。幀更新循環(huán)的第一部分仍然相同:查詢(xún)輸入,更新游戲邏輯,然后渲染場(chǎng)景。但接下來(lái),系統(tǒng)不再是交換緩存,而是在渲染時(shí)將幀,以及視圖姿態(tài)提交給異步時(shí)間扭曲,這樣系統(tǒng)就可以在最后一刻進(jìn)行修改以匹配更新的視圖姿態(tài)。時(shí)間扭曲的巧妙之處在于丟幀發(fā)生時(shí)的情形。時(shí)間扭曲并不只是將顯示器鎖定在最后渲染的內(nèi)容,它會(huì)利用前一幀,但執(zhí)行與更新視圖姿態(tài)相同的邏輯,這樣即便世界的時(shí)間狀態(tài)已經(jīng)發(fā)生改變,你的視圖都能匹配真實(shí)世界。
1. VSync & Virtual VSync
垂直同步(VSyncl;Vertical Sync)又可以稱(chēng)為“幀同步(Frame Sync)。這種系統(tǒng)已經(jīng)出現(xiàn)多年時(shí)間,而游戲引擎主要是用它來(lái)匹配物理顯示器的刷新率。對(duì)于VR,由于顯示器的實(shí)際繪制交給了異步時(shí)間扭曲,所以它同時(shí)負(fù)責(zé)VSync。每一陣都需要固定的時(shí)間量,所以如果從這一點(diǎn)開(kāi)始計(jì)算,我們可以定義所謂的Virtual VSync(V-VSync),亦即所有游戲處理都可以圍繞它進(jìn)行。
請(qǐng)參閱上面的時(shí)間表,它暫時(shí)忽略了游戲過(guò)程。你可以看到,對(duì)于每一幀時(shí)間扭曲都需要少量的CPU時(shí)間,然后在運(yùn)行VSync時(shí)需要一段GPU時(shí)間。因此,在運(yùn)行V-VSync時(shí)游戲必須確保幀可供使用,以便時(shí)間扭曲能夠處理它們。這當(dāng)然只是一個(gè)簡(jiǎn)化的模型,目的是為了介紹時(shí)間扭曲所需的處理。
2. Simplest Game Loop
最簡(jiǎn)單的游戲循環(huán)都有一個(gè)執(zhí)行游戲邏輯的CPU線(xiàn)程:將渲染命令發(fā)送到GPU,然后調(diào)用SubmitFrame,亦即等待下一個(gè)V-VSync。類(lèi)似下圖:
如你所見(jiàn),游戲邏輯和渲染發(fā)生在一幀長(zhǎng)度之內(nèi),而且時(shí)間扭曲能夠立即使用渲染幀。從游戲角度來(lái)看,這將涉及最低的延遲。如果你的GPU沒(méi)有及時(shí)完成渲染,時(shí)間扭曲將不得不使用最后一幀,并導(dǎo)致渲染幀被丟棄。因?yàn)橄乱粠腃PU工作可以在當(dāng)前幀的GPU工作仍在運(yùn)行時(shí)運(yùn)行,所以最終你可能是以全幀速率運(yùn)行,但會(huì)出現(xiàn)多個(gè)過(guò)時(shí)幀。因此,與實(shí)際幀速率相比,過(guò)時(shí)幀的數(shù)量是更重要的監(jiān)控度量。
更糟糕的事情是,GPU渲染時(shí)間超過(guò)下一個(gè)V-VSync。前一幀需要重復(fù)使用兩次,而下一幀的SubmitFrame調(diào)用會(huì)被阻止,直至當(dāng)前幀完成渲染。這為GPU趕上CPU提供了時(shí)間,但同時(shí)意味當(dāng)N+1幀最終顯示時(shí),這將出現(xiàn)一整幀的延遲。
事實(shí)證明,在一個(gè)VSync的正常范圍內(nèi)執(zhí)行全幀渲染是非常難以實(shí)現(xiàn)的目標(biāo),因?yàn)镃PU時(shí)間、GPU時(shí)間加起來(lái)需要不到一幀(如72hz時(shí)是13.89ms,60Hz時(shí)是16.67ms)。實(shí)際上,幾乎每款游戲都需要更多的時(shí)間。因此,Oculus API支持一種名為“Extra Latency Mode(額外延遲模式)”的功能。額外延遲模式令錯(cuò)過(guò)這一小窗口變成預(yù)期的行為,并始終使用為前一幀提交的幀。所述模式的圖例如下所示:
這樣做的最大優(yōu)勢(shì)是,你可以為CPU和GPU利用完整一幀,所以你可以接近于實(shí)現(xiàn)100%的利用率。當(dāng)然,缺點(diǎn)是丟失一幀延遲。Oculus認(rèn)為,這樣的權(quán)衡折中非常值得,乃至于Unity或Unreal 4都默認(rèn)開(kāi)啟額外延遲模式.
如果一切都按時(shí)運(yùn)行,結(jié)果當(dāng)然是顯而易見(jiàn),但如果CPU或GPU需要更長(zhǎng)的時(shí)間才能完整幀的渲染呢?實(shí)際上,GPU的情況與這樣一種情況非常類(lèi)似:當(dāng)一幀需要兩個(gè)以上的V-VSyncs完成渲染時(shí),額外延遲模式?jīng)]有啟用。遲到的一幀將導(dǎo)致下一幀的SubmitFrame調(diào)用被阻止。正如在關(guān)閉額外延遲模式時(shí)的情況一樣,當(dāng)回到預(yù)期的幀周期時(shí),你將呈現(xiàn)至少3個(gè)高延遲幀(前一個(gè)重復(fù)幀,當(dāng)前幀和下一幀)。所以,避免GPU運(yùn)行過(guò)長(zhǎng)時(shí)間對(duì)游戲的流暢度而言至關(guān)重要。
CPU的情況沒(méi)有那么多問(wèn)題。在啟用額外延遲模式時(shí),在V-Vsync返回后立即調(diào)用SubmitFrame(假設(shè)前一幀已經(jīng)準(zhǔn)備就緒)。例如:
如你所見(jiàn),果CPU花費(fèi)的時(shí)間繼續(xù)超過(guò)幀時(shí)間,GPU最終將花費(fèi)過(guò)長(zhǎng)的時(shí)間,而SubmitFrame會(huì)被阻止。但如果CPU時(shí)間減少,游戲?qū)⒒謴?fù),應(yīng)用程序?qū)⒂肋h(yuǎn)不會(huì)丟失幀。
3. 多線(xiàn)程應(yīng)用
盡管單線(xiàn)程應(yīng)用程序最為簡(jiǎn)單,但運(yùn)行Oculus軟件的移動(dòng)設(shè)備(Gear VR,Oculus Go和Oculus Quest)都擁有具有多個(gè)CPU內(nèi)核的芯片組。因此,你需要多線(xiàn)程應(yīng)用來(lái)利用這些內(nèi)核。Unity和UE4都提供了多線(xiàn)程渲染模式。
對(duì)于這一模式,主線(xiàn)程執(zhí)行游戲邏輯,渲染邏輯則由另一個(gè)線(xiàn)程執(zhí)行。所述線(xiàn)程由渲染線(xiàn)程調(diào)用SubmitFrame進(jìn)行同步,因此要等待V-VSync。當(dāng)V-VSync觸發(fā)幀開(kāi)始時(shí),渲染線(xiàn)程向游戲線(xiàn)程發(fā)送信號(hào),以便在操作當(dāng)前幀時(shí)可以開(kāi)始執(zhí)行下一幀的邏輯。最終效果是,在游戲邏輯和屏幕呈現(xiàn)渲染幀之間發(fā)生一幀的額外延遲。這是一個(gè)例子:
類(lèi)似地,如果渲染線(xiàn)程遲到,則不會(huì)發(fā)送信號(hào)以通知游戲線(xiàn)程開(kāi)始下一幀:
4. UE4 and RHIThread
Ureal 4最近推出了一種名為RHIThread的功能。它將圖形API調(diào)用(對(duì)于Oculus Mobile,這是OpenGLES或Vulkan)的實(shí)際提交與Render Thread完成的其他工作(如剔除和排序等等)分開(kāi)。對(duì)于某些應(yīng)用程序而言,這可以提高性能,因?yàn)殇秩具壿嫃膯螏瑫r(shí)間拆分為兩個(gè)。但是,這需要付出一個(gè)額外延遲幀的代價(jià)。除非必要,否則大多數(shù)應(yīng)用程序都應(yīng)該避免啟用RHIThread,因?yàn)榭傃舆t有可能遠(yuǎn)遠(yuǎn)超過(guò)50ms。
5. 總結(jié)
理解CPU和GPU是如何同步渲染幀是實(shí)現(xiàn)最佳性能的關(guān)鍵。如果你的游戲開(kāi)始丟幀,解決問(wèn)題的第一步是判斷哪個(gè)線(xiàn)程是瓶頸所在?;蛘呷绻阌邢喾吹膯?wèn)題,亦即游戲飛速運(yùn)行,但運(yùn)動(dòng)到光子延遲非常高,你可以通過(guò)降低線(xiàn)程復(fù)雜性來(lái)改善延遲。
原文鏈接:https://yivian.com/news/59536.html
來(lái)源:映維網(wǎng)