【轉】: here緩存
從後緩存到顯示器 架構
最近在看D3D的架構,在這過程當中對幀率這個一直認爲很簡單的東西有了更多的理解。在過去看來,幀率就是顯卡渲染一幀所用時間的倒數,如今看來遠遠不是這個樣子。.net
要真正理解這個問題要從繪製數據從顯存中到屏幕的這一個過程來講起,下圖就是這個過程blog
顯存中存在先後緩存,前緩存就是屏幕上最終看到的像素,然後緩存是繪製使用,後緩存繪製好一幀,一般就交換一次,寫給前緩存,而顯示器則從前緩存不斷的讀取數據。遊戲
交換幀率與刷新幀率get
一般咱們很在乎渲染的效率,其實就是繪製的效率,這就是圖中的f1,也成爲交換幀率,f1決定了顯卡一秒能繪製多少次,之前一直覺得這就是用戶的幀率了,其實不是,由於還有其餘因素。同步
咱們看到顯示器讀取前緩存也存在一個頻率,即f2,f2也被稱爲顯卡的刷新頻率,即顯卡按照多少的頻率去講前緩存的數據給顯示器繪製一次,它無論前緩存的數據是不是新的仍是舊的。因而可知咱們最終用戶看到的幀率是f1 和 f2的共同結果。實際的幀率f應該表述爲顯示器所能表現的緩存交換幀率,即在1秒內有多少個後緩存的傳遞到了顯示器。這樣看f=min(f1,f2),即受這兩個幀率的制約了。好比說你渲染很快,一秒繪製60次,可是顯卡一秒只想顯示器刷30次,那幀率最高也只有30,再好比你渲染很慢,由於模型特別大,一秒畫10次,顯示器一秒刷60次,那用戶看到的實際幀率也只有10。到這裏彷佛幀率是被這二者決定的,可是其實還不是這樣。效率
垂直同步與幀率渲染
從圖中能夠看到一點就是前緩存處於被後緩存寫而被顯示器讀的狀態,那麼這過程就極有可能發生讀寫衝突,而顯示器的繪製是從上到下一行行刷新的,一種典型的狀況就是顯示器在讀這一幀時前緩存被寫入新的下一幀數據,那麼顯示器的上部分和下部分將顯示不一樣幀的畫面,這就是常出現的「畫面撕裂」現象,他就是由於緩存交換太快不等顯示器讀完而形成的。硬件
爲了解決這個現象,引入了「垂直同步」的相關技術,垂直同步就是指顯示器從上到下繪製一個完整幀的畫面的一個過程,在這個過程當中,顯卡保證不去改變前緩存,若是這過程繪製好一幀,那麼後緩存發現前緩存在被讀取就不進行交換操做,這樣的結果會保證顯示器繪製不被撕裂,可是也帶來了另外一個問題,就是卡幀率,由於正常的交換幀率被顯示器的垂直同步各類打斷掉,交換幀率大大下降,下降最終幀率。
看來垂直同步與不垂直同步是兩個極端,他們分別表明着最高的畫面完整度與最高的幀率。因此在實踐中就產生了不少種折中的辦法,就是容許顯卡最多在n幀刷新中只打斷一次緩存交換,n越大越接近徹底不用垂直同步,幀率越高,n越小越接近垂直同步,撕裂現象機率越小。垂直同步、不垂直同步和幾種折中其實就對應了D3D9的交換參數的D3DPRESENT_DONOTWAIT、D3DPRESENT_INTERVAL_IMMEDIATE和D3DPRESENT_INTERVAL_ONE(~FOUR)。那麼最終的幀率f應該接近與min{f1-min{f1,f2}/(1+n),f2},一般f2都是足夠大的。
因此幀率不只與交換幀率、刷新幀率有關,還與垂直同步策略有關,因此咱們能夠看到一些玩家的遊戲中關閉垂直同步會卡機,也有一些玩家打開垂直同步會下降幀率,就是這個緣由。
顯存
固然咱們看到垂直同步會制約幀率的時候,是由於咱們這個圖中的的前緩存存只有一處,處於讀寫衝突狀態,那麼會想只要讓顯存不存在這種狀態不就好了嗎,那須要顯存很是大,後緩存是生產者,顯卡是消費者,前緩存若是足夠的大(能夠分紅n多塊),那麼生產者就有可能不用顧忌的往緩存上堆新東西,事實上徹底的不存在衝突是不太可能的,由於顯存的大小永遠存在一個限制,只要緩存大小有限制,就必然可能出現生產者和消費者的衝突,存在衝突,要麼選擇生產者等消費者(生產下降,即幀率下降),要麼消費者拿到的東西會紊亂(即撕裂),可是顯存越大,這種潛在的衝突的可能性就越小,問題就越容易避免。
因此我麼看到顯卡顯存較大的客戶端及時徹底關閉垂直同步(即理論最大幀率)也不太容易撕裂,或者徹底打開垂直同步幀率仍是很是高,顯存不只有利於繪製也有利於解決前緩存衝突提升幀率。
基於這些思考,因此在選擇渲染策略時,必定要充分考慮垂直同步的策略,根據潛在用戶的硬件、遊戲的繪製效率、刷新效率一塊兒考慮,知道幀率是由繪製效率,顯卡刷新效率和垂直同步策略三者共同決定的。在D3D9中微軟推薦使用的垂直同步策略時D3DPRESENT_INTERVAL_ONE,即最接近徹底垂直同步的折中策略,即最多在一次顯卡刷新中打斷一次緩存交換,實際幀率應該是接近於f1/2,若是最終用戶看到的要在30幀的話,z在f2是60的狀況下,那麼f1要在60幀以上。