Direct3d 设备丢失 (device lost)
1.什么時候設備丟失
?
一個Direct3D設備, 有兩種狀態: 操作狀態或丟失狀態。
操作狀態: 是設備的正常狀態, 設備按預期運行, 并且能present所有渲染效果
丟失狀態: 所有渲染操作悄然失敗, IDirect3DDevice9::present返回錯誤碼D3DERR_DEVICELOST
?
查幫助Lost Devices (Direct3D 9)看更詳細介紹,用最民工的語言簡略說說:什么時候設備會丟失?
(1)全屏模式下當前Direct3D窗口丟失焦點時
(2)有多個Direct3D窗口,其中一個進入全屏則其它設備丟失(多顯卡時情況則不同,每個顯卡設備只有一個能全屏)
系統休眠或者鎖定(Win+L)
(3)IDirect3DDevice9::Reset調用失敗時, 設備也會被設置為丟失狀態
(4)重新設置Direct3D device 參數時
?
?
2.如何發現設備丟失
?
?
IDirect3DDevice9::present返回錯誤碼D3DERR_DEVICELOST 或 D3DERR_DRIVERINTERNALERROR(這種情況下基本上要exit了)
IDirect3DDevice9::TestCooperativeLevel返回錯誤碼D3DERR_DEVICELOST或D3DERR_DRIVERINTERNALERROR(DX10整合到present中了)
?
不論通過任何方式發生了設備丟失,所有的操作幾乎都會失效,只有Release()可以用——其實D3D會保證有部分操作可以成功,但
是也僅僅是“可以”成功而不是“一定”成功,所以你還不如認定丟失的時候全都會失敗比較好——以及
IDirect3DDevice9::TestCooperativeLevel。因此在設備丟失之后,你應該停止整個游戲循環,而通過反復調用
IDirect3DDevice9::TestCooperativeLevel判斷設備是否可用。
『IDirect3DDevice9::TestCooperativeLevel』
這個方法檢測當前的設備狀態。返回值有四種:D3D_OK一切正常,D3DERR_DEVICELOST設備丟失,D3DERR_DEVICENOTRESET設備
可以Reset。另外還有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到這個你就完蛋了,基本不可能恢復了,終止程序吧。
按照順序來講,如果游戲在正常運行,D3D_OK會返回;如果發生了設備丟失并且在這個時候不能恢復,比如全屏幕模式的時候
用戶切換到了Windows桌面,就會返回D3DERR_DEVICELOST;如果用戶又切換回了游戲,設備可以恢復了(還沒恢復呢!只是“可
以”恢復而已),就會返回D3DERR_DEVICENOTRESET。
另外,IDirect3DDevice9::Present也會返回類似的值,不過你最好別指望這個,老老實實的用TestCooperativeLevel。因為
Present在設備可以恢復的時候還是返回D3DERR_DEVICELOST(外一句:D3D10的時候TestCooperativeLevel就會完全整合到Present
里面了,可喜可賀可喜可賀)
?
3.發現設備丟失后
?
1.查詢設備狀態, 看是否可以將之恢復到操作狀態. 如果不行, 則必須要等到設備可以被恢復為止.
?
2.釋放所有在D3DPOOL_DEFAULT中分配的資源, 包括用IDirect3DDevice9::CreateRenderTarget和
IDirect3DDevice9::CreateDepthStencilSurface方法創建的資源. (不進行這一步, 下一步的Reset操作會失敗)
?
3.調用IDirect3DDevice::Reset進行恢復. Reset方法是當設備丟失時, 唯一有效的方法, 并且是應用程序可用來把設備從丟失狀態
恢復到操作狀態的唯一方法.
?
4.重建在步驟2中釋放的資源, 同時還需要重新設置state等
?
?4.管理資源
?
1.資源管理是將資源從系統內存提升到設備可訪問存儲器及從設備可訪問存儲器中拋棄的過程
?
2.D3DPOOL_MANAGED標志指定一個由系統管理的資源。由系統管理的資源在設備的丟失狀態和操作狀態間的轉換中持續存在。通過調
用IDirect3DDevice9::Reset設備可以被重置,并且這類資源可以繼續正常運作而無需重新載入圖片。但是,如果設備必須被銷毀和
重建,那么所有用D3DPOOL_MANAGED創建的資源也必須被重建
?
3.D3DPOOL_DEFAULT標志指定把資源放在默認的池中。在默認的池中的資源在設備從丟失狀態到操作狀態的轉換過程中不持續存在,
這些資源必須在調用Reset之前釋放,然后重建
?
4.不是所有的類型和用途都支持資源管理。例如,用D3DUSAGE_RENDERTARGET標志創建的對象不支持資源管理。另外,不建議對需要
頻繁改變其內容的對象使用資源管理。例如,在某些硬件上對一個每幀都需改變的頂點緩存進行自動管理會嚴重降低性能。但是,
對紋理資源來說這不是一個問題
?
5.處理設備丟失
?
下面的偽代碼:
switch (IDirect3DDevice9::TestCooperativeLevel()){
case D3D_OK:
GameLoop();
break;
case D3DERR_DEVICELOST:
break;
case D3DERR_DEVICENOTRESET
OnLostDevice();
IDirect3DDevice9::Reset();
OnResetDevice();
break;
default:
QuitGame();
break;
}
GameLoop()就是你的游戲運行的過程了。把這個switch寫在我們游戲框架的GameMain()部分,具體的位置可以看任何一話附帶
的源代碼。
?????? 好像我一直沒有講IDirect3DDevice9::Reset的參數啊?因為只有一個參數,就是指向D3DPRESENT_PARAMS的指針。把你第
一次創建設備時使用的D3DPRESENT_PARAMS結構保存起來,供Reset來用。
OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的資源,OnResetDevice()就是Create*()恢復啦!你可能注意到
ID3DXFont、ID3DXSprite等等都有同名的方法,就是在這個時候調用的。如果你沒有這么做,也就是說還保留著任何
D3DPOOL_DEFAULT的資源的話,IDirect3DDevice9::Reset就一定會失敗?! ?/span>
?????? 另外在OnResetDevice里面你還要重新進行SetRenderState、SetSamplerState等等,Reset之后這些東西也丟失了。實際上
Reset和重新創建一次設備類似,所不同的是重新創建設備的話你需要連D3DPOOL_MANAGED的資源也Release掉。這個話題就不
討論了。
從代碼可以看出來,D3DERR_DEVICELOST時程序什么都沒做,只是在傻等。我認為這是一個好習慣,因為實在不能保證在
D3DERR_DEVICELOST時除了Release還能干什么,與其這樣還不如等設備能用了再說。
?? 實在懶得管資源的話,全部D3DPOOL_MANAGED好了。至于渲染對象?自己想辦法。
?
6.人工制造“設備丟失
?
“干嘛還要制造設備丟失啊?”如果更改游戲分辨率、色深、切換全屏幕及窗口狀態,進行這樣的操作也要通過Reset,同樣
的,Reset之前也要釋放掉所有D3DPOOL_DEFAULT資源(其實嚴格來說,還有更多的資源也要釋放,不過在2D下基本不會創建這類資
源,你就不用管了)并且調用ID3DXSprite::OnLostDevice之類的方法。這就是人工制造“設備丟失”了。實際上在這個過程設備并
沒有真正的丟失,只是會有一段時間處于不可用的狀態,此時Reset尚未返回,整個D3D設備就好像死了一樣。舉個例子,你切換桌
面分辨率,會有那么一段時間顯示器上什么都不顯示,然后很快就正常了。和這個現象是同一個原因。Reset成功后記得恢復資源。
你可能注意到這里的Reset和上面的Reset不是一回事。的確是這樣,這里是為了重設狀態而不是恢復設備。因此更改分辨率、色
深的Reset需要寫到switch外面,也就是別和它攪和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。記
住:正確的調用Reset不會造成設備丟失,這個概念別弄混了。?
原文來自:http://blog.csdn.net/kuangfengwu/article/details/7674074
總結
以上是生活随笔為你收集整理的Direct3d 设备丢失 (device lost)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Direct3D 11在windows7
- 下一篇: MIT线性代数笔记十七讲 正交矩阵和施密