這個問題挺好的。

為了理解這個問題,首先需要了解什麼是垂直同步。

Analog television?

en.wikipedia.org圖標

早在CRT(顯像管)時代,電視機的畫面是由熱電子撞擊塗在顯像管上的熒光粉發光來進行顯示的。在顯像管的背面,有一把熱電子「槍」,發射出電子束。在電子束和屏幕之間,有電磁線圈,左右一對,上下一對,分別控制電子束的水平偏轉和垂直偏轉。

Cathode-ray tube?

en.wikipedia.org圖標

為了顯示一幅畫面,控制電路通過控制流過線圈當中的電流,改變磁場的強弱和極性,從而改變電子束在水平方向和垂直方向的偏轉角度。就如同我們寫文章一樣,從屏幕的左上角開始,從左到右從上到下一行一行地掃過屏幕的整個顯示區域,激發熒光粉發光,顯示一幅完整的圖像。

圖片來源:維基百科(https://en.wikipedia.org/wiki/Analog_television#/media/File:Raster-scan.svg)

在上圖當中,我們可以看到有兩種虛線。一種是在一行掃描完成之後,從右邊回到左邊的虛線;另外一種是在最後一行掃描完成之後,從右下方回到左上方的虛線。

第一種就被稱為水平同步,而第二種就被稱為垂直同步。在模擬信號時代,它們都有專門的信號與其對應,分別標誌著一行的結束和一幀的結束。

雖然在如今的數字液晶屏(或者等離子、OLED)時代,顯示的原理已經有很大的不同,但是水平同步和垂直同步的概念仍然被保留了下來。我們依然可以認為畫面是這樣一行一行一幀一幀顯示出來的。

而遊戲當中的所謂開啟垂直同步,就是CPU(或者GPU)必須等待上一幀的垂直同步信號,才開始在屏幕上更新顯示下一幀的畫面。這樣做的目的是確保在任何時候,畫面上顯示的所有行都是屬於同一幀的,也就是不會出現前面幾行是上一幀而後面幾行是下一幀的情況,就是平常所說的畫面割裂。

但是僅僅是開啟垂直同步的話,只是限制了CPU/GPU可以向顯示設備推送畫面的時機,其本身並不一定會限制遊戲邏輯(遊戲主循環)的循環頻率。比如,遊戲依然可以跑在120fps,也就是每秒渲染120幅畫面。只不過,最終顯示在屏幕上的只是其中的一部分(60幀),其他的我們看不到而已。

當然,這種情況對於大多數遊戲來說,顯然是沒有意義的,平白浪費了很多計算資源。於是,大多數遊戲引擎當中,會進一步讓CPU/GPU等待第N幀的垂直同步信號之後,才開始N+2幀(此時,N+1幀需要輸出給顯示器進行顯示了)的準備和渲染工作。也就是說,在屏幕顯示第N幀的時候,CPU/GPU在繪製的是第N+1幀(繪製到內存當中的一塊緩衝區,也稱為back buffer);而當顯示器顯示第N+1幀的時候,CPU/GPU在繪製的是第N+2幀。

這就是所謂的雙緩衝機制。我們在玩很多遊戲的時候,會有一個選項,問我們是否要開啟雙緩衝,甚至是三緩衝(CPU/GPU與顯示的內容差2幀)。

在這種情況下,開了垂直同步,其實也就是將遊戲鎖定在了屏幕刷新率上。

而如果不開啟垂直同步,直接鎖遊戲的幀率,那麼更多的只是在遊戲的主循環加個限制,讓其按照這個幀率運行。這個時候,CPU/GPU對畫面的更新與屏幕的刷新可能不同步,也就是屏幕的上半部和下半部可能是顯示了兩個相鄰幀的一部分,畫面就會出現割裂。但是這樣做的優點是CPU/GPU可以不必等待外部的垂直同步信號才開始工作,對於幀與幀之間計算量波動較大的情況,對於複雜的幀可以花費更多的CPU/GPU時間來計算,導致的後果可能是畫面撕裂,但是總比跳幀強(在開啟垂直同步的情況下,如果計算不能在下一個垂直同步信號到來之前完成,那麼這幀就可能面臨著被丟棄,也就是跳幀的後果)。


最重要的區別在於:是遊戲自己的代碼在等待,還是驅動在等待。

垂直同步的情況下,遊戲的渲染循環走到Present()的時候,是會跳到遊戲之外的代碼之中,由系統和驅動進行等待,等待完畢再回到渲染循環。這個等待的時間裡面,遊戲代碼本身不能進行任何操作。如果是多線程代碼,呼叫了Present()的線程,通常也就是渲染線程也是無法進行任何其他操作的。什麼時候能返回遊戲也說了不算,只能等待系統結束等待並返回。

遊戲自己鎖60fps的情況,則是遊戲在自己的代碼之中主動等待,等到固定的時間之後再推送Present()或者進入下一個循環(取決於你在哪裡等)。在等待的途中遊戲代碼可以去干點別的,如果是多線程的話,渲染線程可以主動睡下,並設定一個定時器喚醒,或者由其他線程計時並喚醒。

遊戲自己鎖幀的好處是可以避免驅動一下子吃進太多Present()提前緩存多幀導致的輸入延遲。

不過鎖幀和垂直同步並不衝突,可以在鎖幀的前提下開啟垂直同步,系統的垂直同步通常是只要內部渲染隊列沒有填滿,就不會進行等待並立即返回。顯示的時候則會忠實的去「同步」顯示。只要掌握好Timing,遊戲是可以掌握一定的控制權的。不過Windows 8之後有了更好的方法,很少有遊戲單純為了「低延遲」和「掌握控制權」而鎖幀了。


遊戲鎖60fps,照樣發生畫面撕裂

60Hz開V-Sync,畫面完整


做個實驗就好了,我的實驗結果是:

以60HZ屏幕為基礎:

開垂直同步,只要垂直同步不出BUG,畫面絕對不可能出現任何撕裂

關垂直同步,用鎖幀工具把遊戲鎖死為60幀,畫面該撕裂還是撕裂。

這就是區別,但是原理我講不出來,網路上對於VSYNC的定義非常迷糊,就是英偉達也沒說出來個死理。

我想垂直同步絕非僅僅是個限幀工具而已,不然怎麼解釋同是鎖幀不開垂直同步就會畫面撕裂呢


區別在於 垂直同步6060hz的幀生成時間是穩定一致的16.666ms

而鎖60幀的話 幀生成時間可能不一致 有大有小 可能前一幀的生成時間是20ms 後一幀的生成時間可能就是10ms 與顯示器的刷新率就會不一致 依然會有撕裂


鎖幀60:GPU監視幀時,幀時小於1/60秒則暫停渲染,等待到1/60再繼續。大於1/60秒則不涉及。相當於幀數曲線砍掉高頻。

垂直同步:等待屏幕刷新結束再開始渲染,渲染完重複等待。


推薦閱讀:
相关文章