[GDC16] Optimizing the Graphics Pipeline with Compute

Optimizing the Graphics Pipeline with Compute算法


DX12雖然帶來了CPU的low overhead,可是依然GPU會卡在tiny draw上。主要是GBuffer的後面半段dp會由於Hi-Z cull掉不少pixel(從近到遠draw),並且遠處的物體會有大量細節物體。微信

能夠看到後半段,大部分只有vs,沒有ps invoked閉包

樂觀點假設rasterizer每一個cycle能處理2個triangles,實際上xb1是0.9個。由於從VGT->PA使用FIFO隊列,因此在4096個cycle中處理完vs填滿FIFO隊列,纔不會使得rasterizer飢餓(怎麼算出來的)。在shadow pass的表現最差,由於有部分特別大的triangles,coarse rasterizer對於1個tile只用一個cycle就完成了,因此對於大於32*32像素的三角形須要多個cycle架構

大部分引擎在CPU作coarse culling,再在GPU上refine,由於CPU和GPU之間的延遲,不少優化沒法達成。爲此會作一些GPU上的culling,包括Depth-aware culling,late-latch culling以及本篇講的cluster/triangle culling併發

CS處理mesh帶來了一系列好處,最主要的思想就是把drawcall看作data,這些GPU生成的數據能夠pre-built,cached以及reused異步

Overview 以前Ubi的GPU-Driven差很少,略過ide

相互交叉vb的各個attribute會帶來更好的性能。對於compute cull,不用關心其餘數據(uv,tbn等),這樣stride就是一個固定值沒有任何狀態切換。對於vertex數據的cache也更加友好,以前cacheline須要保存很大一塊數據,如今用完相應的數據能夠直接invalid cacheline。另外一方面,對於CPU的數據也由SoA變爲了AoS,更加適合SSE。並且能區分容易改變的和固定的數據,好比pos+uv(畫shadow),skin data等。分開的好處還有一個就是能夠自由重建indexbuffer,對於depth only pass,只須要pos數據,能夠re-use更多的頂點(正常繪製的時候,pos同樣可是uv和normal可能不同 )性能

Cluster Culling。事先使用貪心算法把mesh分紅256個triangle一組的clusters,對於每一個cluster預烘焙一個bounding cone,作法是對這256個法線投到球上,作一個最小閉包的椎體。4個8bit channel的SNorm的精度足夠了,只須要判斷視線和cone normal的夾角是否小於cone的張角。爲了不false reject張角能夠大一些,還能夠對normal進行GBuffer經常使用的encode測試

Occlusion用的是bounding sphere vs bounding box(HiZ),注意在透視投影中sphere會變成ellipsoid優化

在133us開始,由於index爲空因此遇到了empty draw,151us連續10us空閒,實際由於流水打斷須要從新填滿,因此性能損失超過10us。從中能夠看出compact index的重要性

DX12新潮作法

通用作法,在cs中作parallel reduction,在GCN架構中還有其餘奇技淫巧

Parallel prefix sum

Ballot 64bit表明每一個thread的狀態

利用這個

MBCNT計算以前幾個thread的bit累加

兩個結合起來,獲得了prefix sum

看代碼好懂

每一個thread處理一個triangle,經過的culling的會使用剛纔的技巧來得到當前triangle的compact index。對於wavefront之間若是想作半透排序等,須要使用ds_ordered_count來保證wavefront之間的輸出順序。

對於if branch編譯器會作優化來進行divergence execute,實際上沒什麼必要,只有在須要rw的時候才進行branch,好比Hi-Z cull

理論上50%的triangle會被back-face culling,因此須要用效率最高的算法

Tessellation patch back face cull略,沒接觸過

越小的triangle對於raster來講效率越低,由於卡在primitive setup上,raster一直飢餓

這個挺有用的,對於raster的效率能夠寫段可視化代碼測試,對於每個triangle會對應一個wavefront來處理其raster以後的pixel,那麼輸出每一個wavefront中真正有效pixel的thread佔比,就能夠看出是否有太多的瑣碎triangle,另外也能夠測試LOD的設置是否合理

Small primitive cull的幾種狀況

Frustum culling,只作4個plane保守cull

一種方法是若是當前triangle或者cluster的bb徹底在tile內,那麼判斷是否reject,不然保守保留

在作16*16的depth reduction,各類優化41us,對於其餘的好比light tile也使用一樣的代碼

另一種方法,也是frostbite用的就是hierarchical Z pyramid,根據triangle的bb去選擇mipLevel,直接對比depth

AMD HTILE主要就是能夠8*8的depth只用32bit,一個test能夠reject64個pixel。由於是console spec的,後面略

可使用CPU的軟光柵化ZBuffer

使用固定大小的buffer,每次生成大概3MB的indexbuffer,錯開dispatch&draw,更好利用異步來併發流水

起步並非太好

能夠作一些其餘計算

44w面->9w面

GPU 性能提高15%-30%

Tessellation提高更多40-80%

More:【微信公衆號】 u3dnotes 

本文分享自微信公衆號 - Unity3D遊戲開發精華教程乾貨(u3dnotes)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索