新開發的遊戲容易導致顯卡驅動停止,並且成功恢復。如何確認是否是遊戲代碼導致該問題發生?

新開發的遊戲: 64位、dx11.

上面的問題可能出現在各種類型的機器上面。發生這種問題的時候,dx的present failed ,device removed ,然後遊戲黑屏。 微軟有薦的解決方案Handle device removed scenarios in Direct3D 11是重新創建設備,重設資源,然後渲染。 沒用dx11寫過代碼,請教各位有經驗的朋友,1、導致顯卡觸發系統tdr的原因有可能是代碼的原因嗎?2、dx11 會自己處理devide lost, 但是present的其他錯誤都要處理嗎?


以前在一個pc遊戲開發中遇到過類似的問題,具體癥狀就是整個項目組開發過程中,每過兩三天,隨機會有一次藍屏,概率不高,但很噁心。具體細節有點不清晰了,談談解決思路,或許可以參考。

先初步定位。打開windows系統dmp,等待下次藍屏。下次崩潰後,拿到full dump,找了windows的symbol,配合一起看,發現系統崩潰在nvidia的驅動裡面。找nvidia開發者支持,附上dmp,對方也沒有給出太有價值的信息,應該是對方覺得優先順序不高。
第二步就是想辦法穩定重現,看了全項目的歷史崩潰情況,覺得非常偶然,沒有太多線索。無意中發現自動構建機平均每天有一次崩潰,應該是構建以後就會做loading測試,啟動了很多次遊戲。於是徵用這台電腦,專門做loading測試,每天還是穩定可以重現一次,好處是程序員不用介入了,每天下班前去看看dmp就好了。
第三步,用力查,但每次dump信息差不多,查不到有價值內容。於是2分法亂試。注釋掉很多渲染代碼看能不能改變重現規律,說白了就是碰運氣。反正也不佔用太多時間。
第四步,渲染程序員做其它工作的時候,偶然發現有些shader命令會有兼容性問題,有warning,看了一下文檔,懷疑和藍屏有關。改掉,果然後面幾天再也沒有藍屏。
第五步,徹查所有warning和隱患,舉一反三,把相關內容都整理乾淨,杜絕其它類似問題。

再以前做ps2遊戲,也有類似問題,由於這類問題很難穩定重現,很難debug,線索往往隱晦不清,錯誤離問題現場非常遠,所以歷來都是很頭痛的事情。
解決方法就是細心耐心,分析線索,設法提高再現率,用合理科學的方法碰運氣,縮小範圍。

之前寫過幾篇bug往事,可以看看處理疑難問題的一些思路。
Bug往事(1) - 知乎專欄

Bug往事(2) - 知乎專欄

Bug往事(3) - 知乎專欄


在D3D11上,其實device removed很罕見,但一旦遇到就是很嚴重的事情了。常見的原因有幾個

  1. 你的某個Draw/Dispatch所花的時間太長,超過2秒產生了TDR
  2. 某個調用參數錯誤造成越界。這個需要通過debug layer來查看。
  3. 驅動有問題。換個硬體再試試。
  4. 顯卡被拔了。這個可能性也太小了。不過我有一次為了主動產生這個device removed,插了usb的外置顯卡,運行過程中拔掉。。。


顯卡崩潰原因很多,如果確認shader沒什麼大問題(除0,死循環,迭代次數太多之類)那一般是顯卡和驅動問題了,更換驅動和顯卡進行測試。

device lost的處理比較麻煩,輕度的丟失只要重建framebuffer就可以。

完全顯卡崩潰就比較麻煩。

可能資源要全部重新載入,備選方案是把所有資源在內存里做一個備份,設備丟失了自動重新裝載。

DX9時代有個叫Managed Resource (https://msdn.microsoft.com/ja-jp/library/bb147168(v=vs.85).aspx) 就是用來對應這種狀況的。DX11上沒有,需要手動寫一套。


dx9 device lost, dx11 device removed, 都屬於顯卡崩潰,而且沒有100%解決方案,只有一些過往經驗:

1. 如果和顯卡廠商有技術合作,第一時間通知對方。顯卡廠商可以從驅動層找出具體問題。

2. NV 驅動在2015 - 2016年基本上每隔一個版本就會出現崩潰問題,可以更換一個驅動試試。

3. 如果渲染底層是dx11的,打開 directx debug,查看 warning 和 error。error 是肯定要修的,warning 中如果涉及到資源 conflict 也是一定要修的(注)。

4. 排除法,把一些渲染 pass 關閉,看看是否穩定。在怪獵OL中我查到過 NV 某個版本的驅動在優化 compute shader 的按位操作後導致某個彙編指令100%崩潰。這個只能通知顯卡商讓其修復或者自己這邊用其他方法實現你要的東西。

註:資源 conflict 就是當你想使用某個 buff 或者貼圖的時候,其實它還被 GPU hold 住,處於寫的狀態,這種很容易造成顯卡崩潰。這是因為 GPU 內部實際上是並行操作的,但是 dx11 的 immediate context 讓你覺得好像渲染指令都是串列的,而實際上 dx11 內部是如何管理這些並行渲染的,你是不知道的,是由顯卡驅動管理的。比如:

1. 你有貼圖 A,對其創建了 render target A1,和 shader resource A2

2. 你在某個 render pass 中對 render target A1 渲染了些東西

3. 在沒有置空 render target A1 所在的 render target slot 的情況下,就直接使用 shader resource A2,這個時候就會造成 conflict。

4. 同理,在沒有置空 shader resource A2 所在的 texture stage slot 情況下,對 render target A1 進行寫操作,也會造成 conflict。

5. compute shader 所在 pass 尤其敏感,最好在 compute shader pass 結束後將所涉及的 uav 和 shader resource 都置空。


錯誤應該會返回錯誤號,先看錯誤號。對於present failed或者device lost有時候會出現在很莫名的context下。這個問題從經驗看是顯卡廠商配合最方便,各位大神提到的排除法,真的看臉,運氣不好這輩子別想查出來。不過也不是沒有對策,只是解決方案很醜,而且不一定真能解決。主要思路就是遇到這個問題時候,再給顯卡一次機會....另外API調用順序要注意,我發現有時候寫的東西運行起來很大概率沒事,但是其實有問題,後來發現是調用順序導致。


出現這種情況最直接原因是驅動寫入的GPU指令有問題,可能是你的代碼問題也可能是驅動bug,可以關TDR 然後看dump找線索。反正代碼是你寫的,一點一點刪掉排除總能找到原因。


因為dx11沒有dx9那樣的managed resouce,所以dx11的遇到device remove基本和dx9里處理revice lost後處理default resource一樣 需要全部重新創建,其實好多dx11的遊戲遇到這種情況直接就掛了根本不會去恢復,因為太麻煩,一般都是逆向去找原因,大部分調試方法樓上的幾位總結的差不多了,這裡補充下今年的GDC 2017 nvidia介紹了一款專門用來調試這種gpu crash的工具 NVIDIA Aftermath ,原理和我們開發階段在渲染pipeline上打flag一樣,允許程序在gpu timeline上自定義一些flag, gpu crash發生後能夠查到最後一個執行的flag是哪個,可以通過這種方式來逐步定位最終的crash點,而且這個工具開銷很低可以直接發布到用戶機器上(支持dx11和dx12),不過目前為止還沒有開放下載,估計快了,強烈建議等可以下載了試試這個工具

(詳細介紹見GDC vault :NVIDIA Aftermath: A New Way of Debugging Crashes on the GPU )


推薦閱讀:

如何看待NVIDIA新驅動被曝強制捆綁遠程插件這件事?
為什麼 NVIDIA 更新其 Windows 顯卡驅動時不用非得重新開機?

TAG:遊戲開發 | 顯卡驅動 | 渲染 | DirectX |