如何評測shader的效率?

在做shader優化的時候,最簡單的是降低數據存儲的精度,但是在評測效率的時候只能通過擺放很多模型做極限的測試(後邊想想在動態的實時渲染環境里也不太靠譜),那天聽一個人說shader的效率和GPU的架構有關係,要關注往GPU寄存器里讀取和存儲數據的個數。但沒太聽懂,想問問各位大神,這個究竟該怎麼評測shader的渲染效率?有哪些必備基礎知識?


理論上,由於現代的圖形架構是管道(pipeline)形式,要用具體執行環境來評測一個shader的效率,需要讓該shader成為瓶頸,然後量度其吞吐量(throughput)。

然而,有幾個因素造成上述的方法無用或無效:

  1. 在遊戲開發中,除了遊戲機和街機平台,一般的目標平台(硬體、操作系統)並不是完全固定的。屏幕解析度也是可變的。
  2. 遊戲過程有很多變數,例如渲染1個接近鏡頭的NPC和渲染10個遠離鏡頭的NPC,其性能分別難以預測。瓶頸經常會改變。

有一些shader是較容易評測的,例如,全屏後期處理的瓶頸在於pixel shader、紋理採樣和帶寬,其運行複雜度與屏幕解析度成正比。

對於其他shader,最簡單的評測方式是,觀察shader源代碼編譯成彙編之後的一般指令及紋理採樣指令數目。這是一個非常粗糙的評測方式,但可以用於作一些簡單的統計,找出那些可能有問題的shader。這適合像UE給美術隨意創建shader的情況。

但在遊戲開發中,我看到一般的做法是,以執行遊戲來作整體評測及優化,而不是單獨評測各個部分。一方面是因為遊戲有很多變數,另一方面是因為人力成本。所以通常會做一些自動評測整體性能的測試,例如讓Bot在場景中行走,記錄整體的幀率、CPU/GPU時間、draw-call等。如自動測試程序發現超出預期的數值,就發電郵通知團隊。這種測試每天自動執行,可畫出按天數的性能圖表,知道開發及優化的整體情況。

因為題目不是問優化,就不詳述優化方法了。但很重要的是,圖形程序員應該對圖形系統的架構有基本認識,了解shader語言各指令及其編譯後的指令,能寫出合乎常識的shader。

最後,推薦Emil Person在這兩年的GDC講義 Humus - Articles:

  • Low-Level Thinking in High-Level Shading Languages
  • Low-level Shader Optimization for Next-Gen and DX11

lz聽的那個人說的是比較對的。
shader的執行是和GPU架構有關係,而且一般談到這個shader執行也不能把texture fetch這些分開,所以要考慮到ALU執行,數據讀取等因素。
而這一點上不同GPU則是在計算單元,紋理處理單元以及內存吞吐量上有很大差別。

首先是硬體平台以及結果的細節
lz首先需要設定出自己的目標平台和架構,然後以其中有代表性的為基礎來進行評測以及優化(這個方法不完美,但是實際中不可能面面俱到,只能如此了)。這個結果有可能出現在A GPU上跑的更快了,但是在B GPU上卻慢了,這個是有可能的,但是不是特別經常出現,出現在不同類型顯卡(Nvidia,Amd,Intel等)上面,可以區別對待。

在沒有培養出很好地經驗之前(其實老手也常常預估錯誤),推薦使用像NSight這樣的工具,可以在硬體級別上看到shader的耗費出在什麼地方。
比如下圖是當時做instancing時候profile出的問題,看到問題出在vertex shader輸入時候,L2 cache效率不好,就可以針對性的降低輸入數據結構大小,把計算分配到別的單元上去做平衡。

這個過程做多了,可以培養出較好的經驗(能從知識推到定量性能的感覺),然後可以1,2次就寫出很高效的shader了。知識點
主要集中在shader在GPU中的執行情況,這個大部分可以通過nvidia的官方文檔獲得,了解gpu運作過程的硬體都怎麼執行的(比如shader編譯出來使用的register過多的話,在一些平台上會導致並行性下降,這個時候拆成兩個pass會更高效)
shader本身,可以關注編譯出來的彙編代碼,比如可以看看mul(vector, matrix)和mul(matrix, vector)編譯出彙編語句會有什麼不一樣,branch語句編譯出來是什麼等等。
稍微說點就是GPU中執行的是機器碼,並非我們在一些profile/debug工具中看到的shader彙編語句,實際中是會實時的把彙編編譯成機器碼,然後在GPU上執行,這個過程中會隱藏注入很多東西,連顯卡公司的人也常常說不清楚,更別說使用的開發者了。
所以也不能太相信自己的經驗,開發中驚喜無處不在,以實際的測試數據為準。


nvidia在若干年前有一份 GPU編程指南,我記得是針對gf6xxx系列的顯卡寫的,到如今來看依然能夠作為入門之用,而且有中文版。這個文檔裡面有很多基礎的知識。

另外我記得gpu gems 1 裡面也有關於如何profile的文章。

怎麼評測shader的效率,無非就是在一個確定的平台上收集數據、分析推測、再收集數據、再分析推測,,,,,,

我在此補充幾點
1、確定一個明確的軟硬體平台,這個是profile的基礎。例如你可以定為,在xx硬體、xx操作系統、xx驅動版本

2、如果你只想profile某一個shader,你最好首先讀懂這個shader。搞清楚shader的意圖,確保shader裡面沒有明顯的錯誤,確保所有的指令都是恰如其分的。

3、掌握好各種工具,有的引擎提供了內置的性能分析,你還可以藉助perfkit、gpa、pix等等工具


如果問題是在問shader代碼的優化問題,對於shader效率基本上可以分幾個點

1 代碼越短越好
2 memory access越少越好
3 if 越少越好
4 少用高級函數,如sin等
5 以前盡量合併成vector計算,例如vec4,現在的amd gcn架構上這個優化失效。


當遇到懷疑的性能問題時,評測一般要控制好變數,同一個場景同一個角度同一個位置。當懷疑shader有性能問題時,不如直接把shader改成返回一個固定的純色。如果幀率沒有什麼變化,基本跟fragment shader沒啥關係了。


個人的經驗,在PC端不同GPU架構導致渲染瓶頸的可能性很小。往往關注指令數目、訪存次數、branch指令、CPU到GPU的吞吐、壓縮PASS的數目等優化就足夠了。
而在移動遊戲開發中,則需要特別關注GPU的架構,如有些GPU上做alpha test會出奇的慢,並且大多數GPU採用的是tiled架構,多PASS對於性能就會是個惡夢。這時首先應該做的是查閱GPU供應商的specification,再做針對性的優化。
不論怎樣,我認為除非經過profile,確認瓶頸是出在Cache、寄存器上,再去考慮彙編等層面的優化才是有意義的。


降低精度會不會提升效率要看文檔 看測試結果,我記得nintendo的文檔列了不少 換半精度他也不會優化的例子。
所以正確的方法是用profiler的工具,結合文檔,看對shader的分析數據,平台與庫的相關文檔會提供具體shader的優化建議,按我的經驗就是 逐條擼。逐條測試。
rt3裡面對優化提供的基本思路就是1區分平台,2找bound。


一般來說 減少相對定址 能用float別用double 盡量少用寄存器 減少分支 特別是動態分支 少用超越函數 減少tex load 少用類似fog alpha test alpha2mask這類技術


推薦閱讀:

遊戲模型(3A)和影視模型(cg)的區別以及發展前景?
無聊買了塊數位板想學CG,請問有哪些關於painter的書籍適合初學者的?或者其他的配搭軟體方面的書籍相對容易上手一點?
如何評價恥辱/羞辱:界外魔之死(Dishonored: Death of the Outsider)?
暴雪和拳頭原畫區別在哪裡?
繪畫中的圖形感是什麼?

TAG:遊戲開發 | Unity遊戲引擎 | CG | 計算機圖形學 |