1. 程式人生 > >粗略判斷Shader每條程式碼的成本

粗略判斷Shader每條程式碼的成本

↓↓↓↓↓↓↓↓↓

Unity對Shader檔案進行編譯的時候,DX9和DX11的版本會直接生成彙編碼。

length(i.worldPos)

DX9

dp4 r0.x, v0, v0
rsq r0.x, r0.x
rcp_pp oC0, r0.x

DX11

dp4 r0.x, v1.xyzw, v1.xyzw
sqrt o0.xyzw, r0.xxxx

由於這些程式碼是最終的指令,大部分指令執行時間是“差不多”的,可以用來預估計算量。但移動平臺則是各廠商驅動各自進行的編譯,各家都不一樣,不好判斷。

但DX9畢竟針對的是非常古老的硬體,很難想象現代GPU還會和它保持一樣。實際的指令應該會更接近於DX11。

以下為列表(用|隔開的資料,前面的部分是計算單分量時的指令數,後面的部分是計算float4時的指令數)
在這裡插入圖片描述


總結一下便是:

  • 反三角函式非常費
  • abs和saturate是免費的
  • 除了反三角函式外,fmod和smoothstep比預期更費
  • log,exp,sqrt(單分量)的成本實際上很低,所以由他們組合成的pow也不高
  • sin,cos在DX11使用了專門一條單指令,成為了低成本函式

另外還有個基本常識:絕大部分GPU是一次性計算4個分量,計算一個float4和只計算單個float耗時是一樣的。當計算float時,剩下三個分量的時長會被浪費。

然而,每條指令的時間成本確實可能是不一樣的。這個和具體硬體有關。
很難找到移動平臺具體GPU的資料,可以參考下文看看一些主流GPU的情況,相信他們總是有一些共性的。

shader function or instruction cost (performance)

結果是,1/x, sin(x), cos(x), log2(x), exp2(x), 1/sqrt(x)這些指令的時間成本是一樣的,而且和普通的四則運算很接近(個人猜測是通過查表實現的)。
但是sin,cos畢竟在舊硬體上成本較高,由於不清楚硬體的具體情況,還是要儘可能少用。

預估成本還有一個辦法,是根據公開的GPU的GFLOPS(Floating-point Operations Per Second每秒執行浮點運算次數)
GFLOPS網站
來評估每個著色器理論極限算力,便能知道一個著色器裡可以允許多少條基本指令。

這當然很不精確,因為紋理取樣,頂點,光柵化等等眾多成本都沒有考慮在內,但是有一定的參考價值。
iPhone 4s使用的晶片是Apple A5,它的FLOPS是12.8G,螢幕解析度是960x640,分到一幀的一個畫素後,結果是
12.8*1024^3/960/640/60 = 372。

根據FLOPS的定義,時間最短的基本指令“乘加(MAD)”需要花掉2FLOPS,那麼單個螢幕畫素能執行186條指令。
假設Overdraw是5,那麼一個畫素著色器能執行37指令。

雖然37指令這個結果顯然比實際多多了,但起碼是在合適的數量級範圍內。可以通過幀率測試來計算“損耗比例”到底是多少。
而且,這樣做我們其實得到了一個上限值。如果你在畫素單元的指令數超過了37(比如用了兩次atan2),那從物理角度是絕對不可能達到滿幀的。