Beware of GPU memory bandwidth

來源:互聯網
上載者:User

Beware of GPU memory bandwidth    

僅供個人學習使用,請勿轉載,勿用於任何商業用途。

        前段時間,寫了一系列Post-Process effect,包括screen spance的motion blur, 折射,散射等等。大部分shader都非常簡單,無非是把一個full screen quad渲染到螢幕,通常不超過10行ps代碼,不含任何分支和迴圈指令,只需要sm1.4就可以運行。可是當在Geforce 7300GT上,同時開啟多個post process效果做測試時,發現fps掉的非常厲害。檢查了所有代碼,確保已經進行了最大最佳化,但問題依然存在。最後得出結論是fill rate瓶頸,畢竟所有人在講解post process技術時,都會提到填充率是最大的瓶頸。

     為了測試在60fps下可以使用多少post effect,我建立了一個空白項目,查看7300GT在1024 * 768的解析度下,可以渲染多少個帶紋理的full screen quad:

//c# code 
protected override void Draw(GameTime gameTime) 
{ 
    GraphicsDevice.Clear(Color.Black); 

    effect.Begin(); 
    effect.CurrentTechnique.Passes[0].Begin(); 
    for (int i = 0; i < maxQuadCount; i++) 
        quad.Draw(); 
    effect.CurrentTechnique.Passes[0].End(); 
    effect.End(); 
    base.Draw(gameTime); 
} 

//shader 
float2 screenParam; 
texture sourceTexture; 

sampler sourceSpl:register(s0) = sampler_state 
{ 
    Texture = <sourceTexture>; 
    MinFilter = None; 
    MagFilter = Linear; 
    MipFilter = Linear; 
    AddressU = clamp; 
    AddressV = clamp; 
}; 

void FullScreenQuadVS(float3 iPosition:POSITION, 
    out float4 oPosition:POSITION, 
    inout float2 texCoord:TEXCOORD0) 
{ 
    oPosition = float4(iPosition,1); 
    texCoord += 0.5 / screenParam; 
} 

float4 FilmScratchPS(float2 texCoord:TEXCOORD0):COLOR 
{ 
    float3 color = tex2D(sourceSpl,texCoord).xyz; 
    return float4(color,0.02); 
} 

technique Default 
{ 
    pass P0 
    { 
        VertexShader = compile vs_1_1 FullScreenQuadVS(); 
        PixelShader = compile ps_2_0 FilmScratchPS(); 
    } 
} 

      結果大大出乎意料,當數量超過20個,fps就低於60了。1024*768的解析度下,每幀需要填充786432個像素,每秒60幀,每幀20次渲染,可以算出當前填充率大約是0.943 billion pixel/sec. 但7300GT的填充率是2.8 billion pixel/sec !!!. 當然,標準規格僅僅是一個理論值,可是結果相差的也太大了,僅僅是標準的1/3!

     瓶頸究竟是在哪裡呢?是硬體實際效能縮水的一塌糊塗,還是XNA內部代碼造成的?我覺得後者的可能性比較大,於是在Creator Club發帖詢問,後來有人告訴我,這種情況多半是頻寬瓶頸。

     那麼究竟是不是呢?來計算一下上面的代碼使用了多少頻寬:每渲染一個像素時,需要讀取一次RGBA紋理,4byte,把顏色寫入backbuffer,4byte,一次深度讀取和寫入,2 * 4byte, 總共是16byte。每秒60幀,每幀20次渲染,大約是15Gb/s。再看7300GT的頻寬參數,10.7GB/s。顯然,僅僅從資料上來說,確實是頻寬瓶頸。不過你肯定也注意到了,實際效能怎麼可能比理論值高那麼多呢?此時我也不確定究竟是不是頻寬瓶頸,於是把紋理從原來的紋理(1024*768)改為了一張2*2的紋理。再次測試fps馬上有了很大提高,至此,最終確信是頻寬瓶頸。 

     你可能奇怪,為什麼這樣就能確定是頻寬的問題,如何解釋實際值比理論值還高呢?這就要從GPU的硬體構架上來說了。在一般的廣告或者資料中,通常只會看到介紹顯卡有多大顯存,實際上,除顯存以外,GPU和CPU一樣,在晶片上還有一塊高速的緩衝,只不過這塊緩衝通常只有幾KB。當GPU快取命中失敗時,才會訪問顯存,產生頻寬流量。對於2*2的紋理來說,最多隻有16byte,總是能放在緩衝中。通過減少頻寬,提高了fps,這足以說明之前遇到的瓶頸確實是頻寬了,也在一定程度上解釋了為什麼我們的計算結果會比標準參數高那麼多。 

     如果你和我一樣,想到對於full screen quad來說,可以關閉深度讀寫來提高效能,那可能會發現另一個很有趣的問題:關閉深度讀寫幾乎沒有什麼效能提升!在8800GT上的,關閉和開啟深度讀寫,效能僅相差10fps而已。問題出在哪裡?是我們計算頻寬的方法不對,還是前面的推理完全是錯誤的?對於這個問題,我並沒有確切的答案,不過還是找到了一些可以對此進行解釋的資料。對GPU來說,由於要頻繁讀寫color buffer和depth buffer,它們實際上是以一種壓縮的格式存在於顯存中,並且由硬體支援進行非常快速的壓縮和解壓,具體的演算法和原理非常複雜,如果感興趣可以去google一下。這裡可以打一個簡單的比喻來說明為什麼壓縮可以提高效率減少頻寬: 如果把1024*1024的buffer壓縮為64*64的buffer,當向這塊buffer中寫入的資料都一樣時,比如深度都為1,那麼不必依次像1024*1024個像素中寫入資料,而只需要把64*64的資料區塊都標記為1就可以了(這也正是為什麼clear()在現代顯卡上非常快的原因)。我們遇到的情況剛好屬於理想狀態,組成quad的兩個三角形都在深度相同的平面上,而且覆蓋了整個螢幕,這就讓深度讀寫變的異常迅速,也從另一方面解釋了前面提到的實際頻寬比理論計算要低。

     至此,得出3個結論:
1,60fps, 1024*768的解析度下,渲染20個帶紋理的full screen quad就已經達到了7300GT的極限(雖然硬體做了眾多最佳化減少頻寬,這個數字仍然很讓人失望).
2, 像素填充率是一個非常不可靠的參數, 不但受到頂點處理能力的影響( 當然,由於DX10採用了統一構架所以沒有這個問題), 還受到頻寬,採樣延遲等很多因素的限制. 對現代遊戲來說,幾乎所有幾何體都是帶紋理的, 所以在遇到填充率瓶頸以前, 可能早就受制於頻寬瓶頸了.
3. 實際頻寬雖然可能比理論計算值低,但仍然非常容易出現瓶頸,特別是在底端顯卡上。雖然顯卡的計算能力每年都在飛速發展,頻寬的增加卻相對非常緩慢:Geforce 6800 Ultra 35.3G/s, 7950GT 44.8G/s, 8800GTX 86.4G/s,9800GTX 70.4G/s+(是的,你沒看錯,9800的頻寬居然下降了), 280GTX 141G/s. 這裡只列出了Nv每個系列最頂級的顯卡頻寬,實際上中低端產品頻寬還要低很多。

     在實際渲染中,計算頻寬要比上面的full screen quad複雜很多,以下所有操作都會帶來資料流量:
1. 向backbuffer中寫入資料
2. 開啟alpha blend需要讀取back buffer資料
3. 浮點紋理將使資料量翻倍
4. 讀寫深度/模板緩衝
5. 讀取紋理(next gen遊戲通常需要使用大量紋理來渲染物體,是最大的頻寬消費者)
6. 開啟Trilinear mipmapping過濾,每次採樣可能需要讀取8次紋理
7. 頂點資料(上面的討論中我們都忽略了頂點,實際上,頂點也將佔用大量頻寬)

      不要忘了,實際情況下,同一個像素非常有可能被渲染多次(我們並不能保證總是從前向後渲染),輕易就突破數十G的流量。此外還要知道頻寬效率永遠也不可能達到100%,大概只有標準參數的80%左右。

      當然,也有一些簡單的方法可以減少頻寬使用率:
1. 使用mipmap,使用硬體支援的壓縮格式,比如DTX。這是最簡單,也是最容易的方法。不要被前面的第6條迷惑了,對3D渲染來說,mipmap通常可以減少每次提交的紋理大小,而壓縮格式可以獲得最好的緩衝,也許2次讀取就獲得了所需要的資料。
2. 儘可能關閉深度讀寫和alpha blend。
3. 儘可能從前到後渲染。
4.  進行額外的depth pass,充分利用early-z刪除不可見像素。
5. 分離頂點資料。比如把頂點位置和法線,紋理座標放到不同的stream中,在渲染shadow map時,只使用包含位置的stream。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.