不论通过任何方式发生了设备丢失,所有的操作几乎都会失效,只有Release()可以用——其实D3D会保证有部分操作可以成功,但是也仅仅是“可以”成功而不是“一定”成功,所以你还不如认定丢失的时候全都会失败比较好——以及IDirect3DDevice9::TestCooperativeLevel。因此在设备丢失之后,你应该停止整个游戏循环,而通过反复调用IDirect3DDevice9::TestCooperativeLevel判断设备是否可用。
『IDirect3DDevice9::TestCooperativeLevel』
这个方法检测当前的设备状态。返回值有四种:D3D_OK一切正常,D3DERR_DEVICELOST设备丢失,D3DERR_DEVICENOTRESET设备可以Reset。另外还有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到这个你就完蛋了,基本不可能恢复了,终止程序吧。
另外注意:Reset方法是当设备丢失时唯一有效的方法,并且是应用程序可用来把设备从丢失状态恢复到操作状态的唯一方法。Reset失败是可能是应用程序没有释放所有在D3DPOOL_DEFAULT中分配的资源,包括用IDirect3DDevice9::CreateRenderTarget和IDirect3DDevice9::CreateDepthSstencilSurface方法创建的资源。所以用这些方式创建的资源要单独进行释放。利用 D3DPOOL_MANAGED和D3DPOOL_SYSTEMMEM等模式创建的则由系统自动管理,可不必处理。
GB中对设备丢失的处理:
GB中的NiDX9Renderer类中在每帧调用LostDeviceRestore()函数进行Device9->TestCooperativeLevel()检测,进而进行相应的处理。其返回结果为D3DERR_DEVICENOTRESET时会进行Recreate处理。先清理一些buffer和相关纹理的RenderData。然后调用我们各自模块中响应的会调函数进行相关的处理。再device->Reset。调用回调函数部分具体如下:
2 unsigned int uiFuncCount = m_kResetNotifyFuncs.GetSize();
3 unsigned int i = 0 ;
4 for (; i < uiFuncCount; i ++ )
5 {
6 RESETNOTIFYFUNC pfnFunc = m_kResetNotifyFuncs.GetAt(i);
7 void * pvData = m_kResetNotifyFuncData.GetAt(i);
8 if (pfnFunc)
9 {
10 bool bResult = ( * pfnFunc)( true , pvData);
11
12 if (bResult == false )
13 {
14 Error( " NiDX9Renderer::Recreate> Reset notification function "
15 " failed before device reset - FAILING\n " );
16 // Release locks
17 UnlockRenderer();
18 UnlockSourceDataCriticalSection();
19 m_kD3DDefaultBuffersLock.Unlock();
20 return false ;
21 }
22 }
23 }
这需要我们在自己的模块中响应回调函数对要处理的资源做处理。分三步:1.写回调函数 2.加入具体的处理函数 3.将回调函数add进renderer
2 {
3
4 return GUIRender::GetSingletonPtr() -> HandleReset(bBeforeReset);
5
6 }
7
8 bool GUIRender::HandleReset( bool bBeforeReset)
9 {
10
11 if (bBeforeReset)
12 {
13 ReleaseTexture();
14 }
15 else
16 {
17 RecreateTexture();
20 }
21 return true ;
22 }
23
24 // renderer中加入回调函数
25 pkDX9Renderer -> AddResetNotificationFunc(GUIRender::ResetNotificationFunction, this );