显卡底层知识
顯卡底層知識
分類:?硬件相關?GPU?Direct3D?OpenGL?圖形圖像?游戲開發?引擎開發2012-09-19 06:38?162人閱讀?評論(0)?收藏?舉報
原文是<stuttering in game graphics:detection and solutions>由nv的技術總監cem cebenoyan在cgdc12上帶來。
非常好的介紹了很多顯卡底層,從硬件到driver,到windows os的一些知識,受益匪淺。
nvidia在cgdc上一直保持著高水平的presentation,贊!
5個常常會造成圖形性能卡頓的原因:
- shader編譯
- 顯存用光了->使用system memory->paging
- 資源的管理:create/destroy/update
- gpu落后cpu太多幀
- 不好的query:event/occlusion query
- driver層面,每個device維護一個cmd buffer,提交的時候是提交給os
- driver一般會在present的時候flush,但是其他地方也可能flush(應該是cmd buffer滿了,或者強制flush)
- driver最多會存上3個frame的cmd,也就是gpu最多可能落后4幀
- os的graphics scheduler統一進行調配,壓入GPU hardware queue
- gpu進行consume
- umd:user mode driver,處理d3d application, 構建和submit cmd buffer
- kmd:kernel mode driver, 在os的kernel mode運行,管理硬件資源
- 操作系統則在兩種模式之間管理command queue
工具 提到了3個,fraps,nsight,gpuview。 這個GPUView以前還真是沒聽說過,是微軟開發的,開發者的主頁:http://graphics.stanford.edu/~mdfisher/GPUView.html,這哥們截止到現在5篇siggraph。 GPUView可以提供大量的詳盡的信息。 一些細節:
- 如果lock的資源在被gpu使用,那么這個lock函數(在某些flag)就會卡住
- 顯存超出比較多的時候,會出現嚴重的paging
回到典型的5個會造成卡頓的原因:
shader編譯: 我們寫的hlsl,編譯成asm后,在gpu運行的時候會進一步編譯gpu需要使用的機器語言,這個語言是我們開發時候offline生成不了的,因為不同的gpu有不同的指令集,這個過程是driver在運行時刻完成。 一般來講,是在CreateShader時候生成這個機器語言,但是實際中有一些例外:
- 對于一些很復雜的shader會先生成一個能用的,但是優化的不好,然后后面時間富裕了在生成一個高度優化的
- 有些state的轉換會造成shader機器指令的編譯,比如有的gpu會把alpha test變成shader里面的clip語句,進而就不用提供硬件的alpha test,那么這種render state的轉換也會造成shader編譯,一些會造成shader recompile
- shadow map bound/unbound
- 使用的貼圖在fp和非fp格式之間轉換--看來fp的texture會使用特殊的sampling指令吧
- 貼圖和rendertarget的srgb
- 同樣的pixel shader,但是COLORWRITEENABLE的狀態不同
- 使用一些枚舉或者bool來控制static branch,不同的branch的排列都會造成編譯
- d3d9的
- clipplane
- mrt的狀態
- fog
- 一些比較好的建議:
- loading的時候把shader create出來,并且把各個mesh至少都畫一遍,這樣保證runtime的時候就不用recompile了
- streaming的話,就render一個看不見的物體好了,反正保證畫一遍
- 如果都做不到的話,保證在createshader和使用shader之間有0.5s到1s的時間緩沖
- 把一些嚴重的state放在一起畫,
- 在vista以及后面的os上,資源創建的時候,內存不總是在create的時候分配,很多情況是在第一次被使用的時候
- 大型資源的創建很耗費
- 頻繁的create/destroy會產生碎片,pool會改善這一點
- 一些會造成同步的點,本來gpu和cpu是異步運行,一旦同步就會導致系統停頓,直到同步
- lock系列(在一定的flag下)
- 在release了一個大資源之后,創建一個大資源(oops)
- 一些建議
- lock和map的時候使用discard flag,這個會新創建一個資源,而不是等待gpu使用上一個
- 經常更新的資源使用dynamic&NOOVERWRITE flag,這樣driver會傾向于把資源放到systemmem,一些比較小的vb,ib,tex放到systemmem也ok啦
- 盡量pool,而不是runtime的去create&destroy
- 自己管理的pool,在釋放和重用資源的時候,記住要query一下gpu使用它的情況,這個不像單獨的一個資源有driver幫著管理,自己的pool就要多費些力氣
- 如果一定要runtime的create&destroy,保證先destroy,然后create,一小會的超內存也會讓driver管理內存的時候傻眼
- 顯存的allocate策略是先到先得
- 按照重要性的順序來alloc顯存
- depth stencil
- render target
- frequently used resource : texture
- less used resource:vb,ib,texture
- 重要性一樣的話,大的優先,float point的優先
- 超顯存的問題并不總是一個嚴重問題
- 高頻率使用的資源都放在顯存里了,所以一般不會有嚴重的paging,所以前面說的是大幅度超顯存才是問題
- gpuview里面可以看paging的事件
queued frame 這個一般都是限制gpu不會落后cpu(render thread)超過一幀,但是這里看來似乎并不是最好的策略,如果可以的話落后個多達3幀的話,可以對gpu時間不穩定的情況有更好的容錯。 也就是會更平滑。 但是副作用也是比較明顯的,比如occlusion query就會晚好多幀。
frame落后有api的: IDirect3DDevice9Ex::SetMaximumFrameLatency IDXGIDevice1:: SetMaximumFrameLatency
其他一些會造成性能卡頓
- gpu context switch,比如在graphics pipeline和direct compute pipeline之間切換
- 多個d3d application同時運行的時候,會造成競爭(contention)
- driver的paged/non-paged pool超內存了,xp上面這方面能力相對就差
總結
- 上一篇: 狗狗急性肠胃炎
- 下一篇: 清华集训2014 玛里苟斯